• C++基础知识(一)


    目录

    1. 命名空间  ::

    2. using 声明

    3. 结构体加强

    (1)不需要加struct就可以定义变量

    (2)结构体内可以写函数

    4. 不能进行隐式转换,必须是显式转换

    5. 三目运算符

    6. C/C++中的const

    7. 引用(重难点)

    (1)引用可以作为一个已定义变量的别名

    (2)当定义函数时,按引用传递

    (3)建立数组引用

    (4)引用的本质

    (5)指针引用

    (6)常量引用

    (7)引用的使用

    ① 引用作为函数的参数

    ② 引用作为函数的返回值

    8. 内联函数

    9. 函数的默认参数

    10. 函数的占位参数

    11. 函数传参的三种方式

    12. 创建一个学生类


    1. 命名空间  ::

    1. namespace A{ //A 是空间的名字
    2. int a;
    3. void func()
    4. {}
    5. }

    (1)命名空间只能写在全局;

    (2)可以嵌套;

    1. namespace Aspace {
    2. int a = 1;
    3. namespace B {
    4. int b;
    5. }
    6. }

    (3)命名空间是开放的,可以随时加入新成员;

    (4)命名空间可以取别名;

    1. namespace newSpace = oldSpace;
    2. newSpace:新名字
    3. oldSpace:旧名字

    (5)分文件编写代码时,如果.h中有两个命名空间,但是里边的成员函数或变量重名时,在.cpp中实现函数时需要加上命名空间。eg:

    test.h:

    1. #pragma once
    2. #include <iostream>
    3. using namespace std;
    4. namespace Space1
    5. {
    6. void func();
    7. }
    8. namespace Space2
    9. {
    10. void func();
    11. }

    test.c:

    1. #include "test.h"
    2. void Space1 :: func() //需要在函数名之前加上命名空间的名字
    3. {
    4. cout << "func" << endl;
    5. }

    (6)作用域运算符 ::

    eg:

    1. #include <iostream>
    2. using namespace std; //标准命名空间
    3. namespace Aspace {
    4. int aa = 1;
    5. void func()
    6. {
    7. }
    8. namespace B {
    9. int b = 3;
    10. }
    11. }
    12. namespace Cspace
    13. {
    14. int c = 2 ;
    15. }
    16. int aa = 100;
    17. int main()
    18. {
    19. int aa = 10;
    20. cout << "aa =" << aa << endl; //就近原则,打印局部变量aa的值
    21. cout << "::aa =" << ::aa << endl; //如果::前边没有东西,则表示取全局的作用域,打印全局变量的aa
    22. cout << "Cspace::c =" << Cspace::c << endl; //::前边加上命名空间的名字则打印命名空间中对应成员的值
    23. cout << "Aspace::B::b =" << Aspace::B::b << endl;
    24. system("pause");
    25. return EXIT_SUCCESS;
    26. }

    输出为:

    1. aa =10
    2. ::aa =100
    3. Cspace::c =2
    4. Aspace::B::b =3

    2. using 声明

    1. #define _CRT_SECURE_NO_WARNINGS
    2. #include <iostream>
    3. using namespace std;
    4. namespace A {
    5. int a = 1;
    6. int b = 2;
    7. int c = 3;
    8. }
    9. void test01()
    10. {
    11. //using声明是让命名空间中某个标识符可以直接使用
    12. using A::a;
    13. cout << a << endl;
    14. int a = 50; //错误,因为using声明了某个变量,在该作用域内不能定义同名的变量
    15. }
    16. void test02()
    17. {
    18. //using 编译指令,让某个命名空间中的标识符都可以直接使用
    19. using namespace A;
    20. cout << a << endl;
    21. int a = 10; //这里没错,因为这里类似于命名空间中的a为全局变量,而这个a是局部变量
    22. }

    3. 结构体加强

    (1)不需要加struct就可以定义变量

    1. struct Maker
    2. {
    3. char name[64];
    4. int age;
    5. };
    6. void test()
    7. {
    8. Maker a;
    9. }

    (2)结构体内可以写函数

    1. struct Maker2
    2. {
    3. int a;
    4. void func()
    5. {
    6. cout << "func" << endl;
    7. }
    8. };
    9. void test()
    10. {
    11. Maker2 a2;
    12. a2.func();
    13. }

    4. 不能进行隐式转换,必须是显式转换

    1. void test()
    2. {
    3. char* p = (char*)malloc(64);
    4. }

    5. 三目运算符

    (1)C语言中,三目运算符返回的是右值,不能被赋值;

    1. void test()
    2. {
    3. int a = 10;
    4. int b = 20;
    5. printf("%d",a > b ? a : b);
    6. //(a > b ? a : b) = 100; //err
    7. }

    (2)C++中,三目运算符返回的是左值,是空间,可以被赋值;

    1. void test()
    2. {
    3. int a = 10;
    4. int b = 20;
    5. (a > b ? a : b) = 100;
    6. cout<<"a ="<<a<<endl;
    7. cout<<"b ="<<b<<endl;
    8. }

    输出为:

    1. a=10;
    2. b=100;

    6. C/C++中的const

    CC++
    const修饰的变量会被存储在只读数据段,只要有定义即分配内存空间全局const当声明extern或者对变量取地址时,编译器才会分配存储地址,变量存储在只读数据段
    局部const存储在堆栈区,不能直接改变变量的值,可以通过指针间接修改const的值

    只有在分配了内存后,才能通过指针间接修改const变量的值。

    ① 对于const int a = 10这种,编译器会进行优化,将a替换为10,类似于#define;

    ② 如果用一个变量初始化const,比如const int a = b,那么也会给a分配内存;

    ③ 对于类对象,也会分配内存,如下代码所示。

    默认为外部连接,当两个c文件中都有同样的const变量时,编译器会报重定义错误默认为内部连接,不会报重定义错误。如果想让C++中的const有外部链接,必须显式声明为:extern const int a = 10;
    1. const Person person; //未初始化age
    2. //person.age = 50; //不可修改
    3. Person* pPerson = (Person*)&person;
    4. //指针间接修改
    5. pPerson->age = 100;
    6. cout << "pPerson->age:" << pPerson->age << endl;

    输出为:

    pPerson->age:100

    7. 引用(重难点)

    (1)引用可以作为一个已定义变量的别名

    1. void test02()
    2. {
    3. int a = 10;
    4. int& b = a; //给a的空间取别名叫b
    5. b = 100;
    6. cout << a << endl;
    7. }

    输出为:100

    而指针的写法是:

    1. void test02()
    2. {
    3. int a = 10;
    4. int* b = &a;
    5. *b = 100;
    6. }

    (2)当定义函数时,按引用传递

    1. void func(int &b)
    2. {
    3. b = 100;
    4. }
    5. void test()
    6. {
    7. int a = 10;
    8. func(a);
    9. cout << "a = " << a << endl;
    10. }

    输出为:a = 100

    而C指针的写法是:

    1. void func(int *b)
    2. {
    3. *b = 100;
    4. }
    5. void test()
    6. {
    7. int a = 10;
    8. func(&a);
    9. cout << "a = " << a << endl;
    10. }

    引用的注意:

    • ① & 在此不是求地址运算,而是起标识作用;
    • ② 引用创建时必须初始化;
    • ③ 引用一旦初始化后不能改变它的指向
    • ④ 必须引用一块合法的内存空间

    (3)建立数组引用

    1. int main()
    2. {
    3. int arr[] = { 1,2,3 };
    4. //第一种方法
    5. typedef int(Arr)[3]; //定义数组类型
    6. Arr &arref = arr; //建立引用
    7. //第二种方法,直接定义引用
    8. int(&arref2)[3] = arr;
    9. for (int i = 0; i < 3; i++)
    10. {
    11. cout << arref[i] << endl;
    12. }
    13. }

    (4)引用的本质

    C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。

    1. int main()
    2. {
    3. int a = 10;
    4. int& aRef = a; //自动转换为int* const aRef = &a;这也能说明引用为什么必须初始化
    5. aRef = 20; //内部发现aRef是引用,自动帮我们转换为: *aRef = 20;
    6. }

     如下图所示:

    (5)指针引用

    在C语言中,如果想改变一个指针的指向,而不是它所指向的内容,则会使用二级指针,如下:

    1. void func(char** tmp)
    2. {
    3. char* p = (char*)malloc(64);
    4. memset(p, 0, 64);
    5. strcpy(p, "hello");
    6. *tmp = p;
    7. }
    8. void test()
    9. {
    10. char* mp = NULL;
    11. func(&mp);
    12. cout << mp << endl;
    13. }

    改成引用的话:

    1. void func(char* &tmp)
    2. {
    3. char* p = (char*)malloc(64);
    4. memset(p, 0, 64);
    5. strcpy(p, "hello");
    6. tmp = p;
    7. }
    8. void test()
    9. {
    10. char* mp = NULL;
    11. func(mp);
    12. cout << mp << endl;
    13. }

    (6)常量引用

    定义格式:

    const int& ref = val;
    1. int main()
    2. {
    3. //普通引用
    4. int a = 10;
    5. int& tmp = a;
    6. tmp = 20;
    7. //int &ref = 10; err,不能给字面量取别名
    8. const int& tmp1 = 10; //可以给const修饰的引用赋予字面量
    9. //编译器会把上边的代码变为:int x=10; const int &tmp1=x;
    10. //tmp2 = 20; err
    11. }

    (7)引用的使用

    ① 引用作为函数的参数

    1. void func(int& a, int& b)
    2. {
    3. int sum = a + b;
    4. cout << "sum = " << sum << endl;
    5. }
    6. void test()
    7. {
    8. int a = 10;
    9. int b = 20;
    10. func(a, b);
    11. }

    ② 引用作为函数的返回值

    如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待。当函数返回时,引用关联的内存一定要存在。

    1. int& func()
    2. {
    3. int b = 10; //不能返回局部变量的引用
    4. int& p = b;
    5. return p;
    6. }
    7. int& func2()
    8. {
    9. static int b = 10;
    10. return b;
    11. }
    12. void test()
    13. {
    14. cout << "func=" << func() << endl;
    15. func() = 100; //如果要函数当左值,那么该函数必须返回引用
    16. cout << "func2()=" << func2() << endl;
    17. }

    8. 内联函数

    内联函数为了继承宏函数的效率,没有函数调用时的开销,又可以像普通函数那样,可以进行参数、返回值类型的安全检查,又可以作为成员函数。

    内联函数也占用空间,但是相对于普通函数,只是省去了函数调用时的压栈、跳转、返回的开销,可以理解为内联函数是“以空间换时间”

    在普通函数前加上 inline 关键字使之成为内联函数。但是必须注意,函数体和声明结合在一起,否则编译器将它作为普通函数来对待。

    inline void func(int a); //该写法没有任何效果

    类内部的内联函数:

    类内部定义内联函数时并不必须要加 inline,任何在类内部定义的函数自动成为内联函数。

    c++内联编译会有一些限制:

    • 不能存在任何形式的循环语句;
    • 不能存在过多的条件判断语句;
    • 函数体不能过于庞大;
    • 不能对函数进行取址操作;

    9. 函数的默认参数

    1. int func(int a, int b = 0) //b=0即为b的默认值
    2. {
    3. return a + b;
    4. }

    注意:

    • 函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数。
    • 函数声明和函数定义不能同时设置默认参数。

    10. 函数的占位参数

    1. void func(int a, int b, int)
    2. {
    3. cout << "a+b = " << a + b << endl;
    4. }
    5. void func2(int a, int b, int=20)
    6. {
    7. cout << "a+b = " << a + b << endl;
    8. }
    9. int main()
    10. {
    11. func(10,20); //err,占位参数也是参数,必须传参数
    12. func(10,20,30); //ok
    13. func2(10,20); //ok
    14. func2(10,20,30); //ok
    15. return EXIT_SUCCESS;
    16. }

    后边讲的操作符重载的后置++要用到这个。

    11. 函数传参的三种方式

    值传递、指针传递、引用传递

    1. //值传递
    2. void swap(int a, int b)
    3. {
    4. int tmp = a;
    5. a = b;
    6. b = tmp;
    7. }
    8. //指针传递
    9. void swap2(int *a, int *b)
    10. {
    11. int tmp = *a;
    12. *a = *b;
    13. *b = tmp;
    14. }
    15. //引用传递
    16. void swap3(int &a, int &b)
    17. {
    18. int tmp = a;
    19. a = b;
    20. b = tmp;
    21. }
    22. void myprint(int& a, int& b)
    23. {
    24. cout << "a=" << a << "b=" << b << endl;
    25. }
    26. int main()
    27. {
    28. int a = 10;
    29. int b = 20;
    30. swap(a,b);
    31. myprint(a, b);
    32. swap2(&a,&b);
    33. myprint(a, b);
    34. swap3(a,b);
    35. myprint(a,b);
    36. }

    上述三种交换结果,只有第一种值传递无法交换a,b的值。

    12. 创建一个学生类

    1. class Student
    2. {
    3. public: //公有
    4. void setName(string Name) //成员方法,也叫成员函数
    5. {
    6. name = Name;
    7. }
    8. void setID(int Id)
    9. {
    10. id = Id;
    11. }
    12. void myprint()
    13. {
    14. cout << "姓名:" << name << "\n学号:" << id << endl;
    15. }
    16. private: //私有权限
    17. string name; //成员属性
    18. int id;
    19. };
    20. int main()
    21. {
    22. Student s;
    23. s.setName("Paul");
    24. s.setID(1);
    25. s.myprint();
    26. system("pause");
    27. return EXIT_SUCCESS;
    28. }

  • 相关阅读:
    如何选择合适的工业相机
    Java 时间的加减处理
    MATLAB中ilu函数用法
    计算机组成原理_Cache写策略
    linux 安装docker
    大学生HTML作业节日网页 HTML作业节日文化网页期末作业 html+css+js节日网页 HTML学生节日介绍 HTML学生作业网页视频
    TypeScript进阶知识之接口(接口定义、接口属性、可索引类型、接口表示函数类型、额外的属性检查、接口继承、接口与类型别名的区别)
    Kubernetes(K8s)上使用分布式存储(Distributed Storage)
    【OS】操作系统高频面试题英文版(1)
    FFmpeg5开发入门教程18:解码内存数据并播放
  • 原文地址:https://blog.csdn.net/woshizuopie/article/details/124789854