今天复习的知识点有五条都相对简单但我们还是都从原理到底层剖析方便大家查漏补缺如果有错误也请大家指正。6.构造函数7.析构函数8.拷贝构造9.const10.static好的我们从第六条开始。6.构造函数构造函数是什么简单来说就是对象的出厂设置是为了给变量赋值而不是初始化。构造函数有三个核心特征第一函数名和类名完全相同。第二绝对没有返回值。第三对象创建时自动调用不能手动调用。构造函数分为三大类无参构造函数有参构造函数拷贝构造函数。其中如果你没有写任何构造函数的时候编译器会自动生成一个无参构造函数但如果你已经写了有参就不会自动生成必须手动书写。有参构造函数带参数的在创建对象的时候会直接传入初始值。最后的拷贝构造函数我们聊完const再来细说。在聊到构造函数是为变量赋值而不是初始化的时候可以向面试官引出初始化列表这也是一个高频考点。●构造函数和类名相同没有返回值也不写void●如果没有实现构造函数编译器会提供默认的无参构造函数●如果没有实现构造函数编译器会提供默认的无参构造函数●构造函数是给成员变量赋值的不是初始化引出初始化参数列表●移动构造继承构造委托构造C11后的写法更加简洁高效7.析构函数与构造函数对应的就是析构函数它的作用就是在对象被销毁之前清理掉它占用的一切资源。他和构造函数对应因此他的特征也十分相像。1.函数名是类名加上~。2.没有返回值且不能携带任何参数。3.一个类只有一个析构函数不能重载。4.对象生命周期结束系统自动调用无法手动调用。这里有一个点如果我们没有写析构函数系统会自动生成但这个函数不会去释放我们在堆区开辟的动态内存这个时候我们必须手动写析构函数释放。class A { int *p nullptr; public: A(int n) //实现了构造函数编译器不提供默认的无参构造 { if (n 0) p new int[n]; //在堆区分配内存 n 个 int 类型的数据 } ~A() { if (p) delete[]p; // 注意释放数组时 一定要加上[]否则只会释放数组的第一个 元素造成内存泄露 } };●对象被释放的时候编译器会自动调用析构函数●析构函数名的为~ 类名没有返回值夜不写void●如果没有实现析构函数编译器会提供默认的析构函数●只要你的类里包含了用 new 开辟的堆内存成员就必须手动写析构函数来 delete 它否则就会造成严重的内存泄漏。8.拷贝构造拷贝构造的核心是通过一个已经存在的同类对象去初始化一个刚刚新建的对象。什么时候系统自动调用拷贝构造1.使用旧对象初始化一个新对象。2.对象以值的形式作为函数的参数或返回值。拷贝构造函数是一种特殊的构造函数他的语法和构造函数十分相像。函数名与类名一致无返回值参数只有一个必须为const Classname 形参对象。为什么必须传引用为什么必须是const拷贝构造的参数如果不是引用会导致无限递归前面加 const 是为了避免通过形参修改实参。深拷贝与浅拷贝深拷贝 拷贝相同大小的内存并且数值也相同浅拷贝简单的赋值操作编译器提供的拷贝构造是浅拷贝一旦你的类里包含了用 new 开辟的堆内存指针浅拷贝就是致命的灾难比如说C2浅拷贝了C1C1内包含一个new开辟的堆内存指针。如果C1生命结束了析构函数释放了这一块堆内存。这时候C2结束析构函数二次释放同一块堆内存编译器就会直接崩溃。但我们使用深拷贝就不会这样因为深拷贝不仅复制指针的值还会重新申请一块新的堆内存把原对象的数据完整地复制过去确保两个对象各自拥有一份独立的资源。深拷贝构造需要手动实现先new一片内存再把数据复制过来。9.constconst向编译器承诺被它修饰的东西是“只读”的绝不允许被修改。以下是它的用法和一些小的细节1.用于定义常量比如说const int MAX_SIZE 100;这时如果去修改MAX_SIZE会直接报错。2.指针与 const 的组合// 1. const 在 * 左边指向常量的指针 const int* p1 a; // 等同于 int const* p1 *p1 30; // 报错不能通过 p1 修改 a 的值 p1 b; // 合法指针本身的指向可以随便改 // 2. const 在 * 右边常量指针 int* const p2 a; *p2 30; // 合法可以通过 p2 修改 a 的值 p2 b; // 报错p2 一旦初始化就“从一而终”不能再指向别处 // 3. const 在 * 两边指向常量的常量指针 const int* const p3 a; *p3 30; // 报错不能改指向的值 p3 b; // 报错不能改指针的指向const 在 * 左边修饰的是指向的内容底层 const表示“不能通过指针去修改指向的值”。const 在 * 右边修饰的是指针本身顶层 const表示“指针的指向不能变”。3.const修饰函数时表示常函数在类的成员函数后面加上 const表示这个函数是一个“只读函数”它承诺绝对不会修改类里的任何成员变量。const 修饰函数时表示常函数1.常函数内的this指针在vs中是 const type * this;(type代表类型)所以常函数内不能修改成员变量也不能调用非常函数因为 this 指针再传递的时候类型不匹配。2.常对象只能调用常函数非常对象既可以调用常函数也可以调用非常函数。3.常函数和非常函数是重载关系因为 this 类型不同可以引导说 this 是怎么来的。4.const 修饰变量时表示变量不可以修改但是可以通过指针来修改代码如下const int a 2; const int *p a; //首先将 p 从 const 类型的指针转换成非 const int* p1 const_castint*(p); //const_cast 这里可以看看 C11 的四种强制类型转换 *p1 3; cout*p *p1endl;简单来说const 修饰的变量如 const int n 0;本质上仍然是一个变量它只是被编译器在语法层面贴上了一个“只读”的标签。当你尝试直接写 a 3; 时编译器会尽职尽责地拦截并报错。但是如果你绕过编译器通过指针直接去操作这块内存*p 3;确实有有希望成功修改它。程序的运行结果完全取决于编译器的心情甚至可能直接崩溃。10.staticstatic 修饰全局变量时如果没有初始化编译器会自动初始化为 0生存周期和全局变量和程序一致只能在当前文件访问如果想在头文件中定义全局变量那么需要定义成静态全局变量因为如果多个cpp 文件引入同一个头文件那么会导致多个 cpp 文件中有相同的全局变量如果没有定义为static 会导致重定义问题。static修饰局部变量时候只做用在局部作用域只会被初始化一次不会随着函数的结束而被释放观察下面代码结果即可得知代码如下void fun() { static int a 1; a; coutaendl; } int main() { fun(); fun(); }运行结果是2 3。static int a 存储在静态存储区。它在程序启动时就被创建直到整个程序运行结束才会被销毁。static 修饰成员变量时●静态成员变量在主函数之前被初始化也就是编译期间初始化●公有的静态成员变量可以通过类名和对象名直接访问●静态成员变量不会占有对象的内存单独的存放在静态区●静态成员变量在继承关系中父类和子类共享●静态成员变量必须在类外初始化●静态成员也可以实现单例模式(可以了解下设计模式中的单例模式)static 修饰成员函数时静态成员函数没有 this 指针因此静态成员函数不能访问非静态成员变量原因无法区分是哪个对象的成员变量静态成员函数不能调用非静态成员函数因为非静态成员函数有隐含参数 this因为静态成员函数无法给非静态成员函数的 this 传值静态成员函数可以调用静态成员变量因为静态成员变量时共享的不需要使用 this 来区分是哪个对象的也可以调用静态成员函数因为静态成员函数不需要给 this 传值。这是今天所有的知识点做好查漏补缺我们明天见
C++知识点复习(面向面试2)
发布时间:2026/5/22 20:43:40
今天复习的知识点有五条都相对简单但我们还是都从原理到底层剖析方便大家查漏补缺如果有错误也请大家指正。6.构造函数7.析构函数8.拷贝构造9.const10.static好的我们从第六条开始。6.构造函数构造函数是什么简单来说就是对象的出厂设置是为了给变量赋值而不是初始化。构造函数有三个核心特征第一函数名和类名完全相同。第二绝对没有返回值。第三对象创建时自动调用不能手动调用。构造函数分为三大类无参构造函数有参构造函数拷贝构造函数。其中如果你没有写任何构造函数的时候编译器会自动生成一个无参构造函数但如果你已经写了有参就不会自动生成必须手动书写。有参构造函数带参数的在创建对象的时候会直接传入初始值。最后的拷贝构造函数我们聊完const再来细说。在聊到构造函数是为变量赋值而不是初始化的时候可以向面试官引出初始化列表这也是一个高频考点。●构造函数和类名相同没有返回值也不写void●如果没有实现构造函数编译器会提供默认的无参构造函数●如果没有实现构造函数编译器会提供默认的无参构造函数●构造函数是给成员变量赋值的不是初始化引出初始化参数列表●移动构造继承构造委托构造C11后的写法更加简洁高效7.析构函数与构造函数对应的就是析构函数它的作用就是在对象被销毁之前清理掉它占用的一切资源。他和构造函数对应因此他的特征也十分相像。1.函数名是类名加上~。2.没有返回值且不能携带任何参数。3.一个类只有一个析构函数不能重载。4.对象生命周期结束系统自动调用无法手动调用。这里有一个点如果我们没有写析构函数系统会自动生成但这个函数不会去释放我们在堆区开辟的动态内存这个时候我们必须手动写析构函数释放。class A { int *p nullptr; public: A(int n) //实现了构造函数编译器不提供默认的无参构造 { if (n 0) p new int[n]; //在堆区分配内存 n 个 int 类型的数据 } ~A() { if (p) delete[]p; // 注意释放数组时 一定要加上[]否则只会释放数组的第一个 元素造成内存泄露 } };●对象被释放的时候编译器会自动调用析构函数●析构函数名的为~ 类名没有返回值夜不写void●如果没有实现析构函数编译器会提供默认的析构函数●只要你的类里包含了用 new 开辟的堆内存成员就必须手动写析构函数来 delete 它否则就会造成严重的内存泄漏。8.拷贝构造拷贝构造的核心是通过一个已经存在的同类对象去初始化一个刚刚新建的对象。什么时候系统自动调用拷贝构造1.使用旧对象初始化一个新对象。2.对象以值的形式作为函数的参数或返回值。拷贝构造函数是一种特殊的构造函数他的语法和构造函数十分相像。函数名与类名一致无返回值参数只有一个必须为const Classname 形参对象。为什么必须传引用为什么必须是const拷贝构造的参数如果不是引用会导致无限递归前面加 const 是为了避免通过形参修改实参。深拷贝与浅拷贝深拷贝 拷贝相同大小的内存并且数值也相同浅拷贝简单的赋值操作编译器提供的拷贝构造是浅拷贝一旦你的类里包含了用 new 开辟的堆内存指针浅拷贝就是致命的灾难比如说C2浅拷贝了C1C1内包含一个new开辟的堆内存指针。如果C1生命结束了析构函数释放了这一块堆内存。这时候C2结束析构函数二次释放同一块堆内存编译器就会直接崩溃。但我们使用深拷贝就不会这样因为深拷贝不仅复制指针的值还会重新申请一块新的堆内存把原对象的数据完整地复制过去确保两个对象各自拥有一份独立的资源。深拷贝构造需要手动实现先new一片内存再把数据复制过来。9.constconst向编译器承诺被它修饰的东西是“只读”的绝不允许被修改。以下是它的用法和一些小的细节1.用于定义常量比如说const int MAX_SIZE 100;这时如果去修改MAX_SIZE会直接报错。2.指针与 const 的组合// 1. const 在 * 左边指向常量的指针 const int* p1 a; // 等同于 int const* p1 *p1 30; // 报错不能通过 p1 修改 a 的值 p1 b; // 合法指针本身的指向可以随便改 // 2. const 在 * 右边常量指针 int* const p2 a; *p2 30; // 合法可以通过 p2 修改 a 的值 p2 b; // 报错p2 一旦初始化就“从一而终”不能再指向别处 // 3. const 在 * 两边指向常量的常量指针 const int* const p3 a; *p3 30; // 报错不能改指向的值 p3 b; // 报错不能改指针的指向const 在 * 左边修饰的是指向的内容底层 const表示“不能通过指针去修改指向的值”。const 在 * 右边修饰的是指针本身顶层 const表示“指针的指向不能变”。3.const修饰函数时表示常函数在类的成员函数后面加上 const表示这个函数是一个“只读函数”它承诺绝对不会修改类里的任何成员变量。const 修饰函数时表示常函数1.常函数内的this指针在vs中是 const type * this;(type代表类型)所以常函数内不能修改成员变量也不能调用非常函数因为 this 指针再传递的时候类型不匹配。2.常对象只能调用常函数非常对象既可以调用常函数也可以调用非常函数。3.常函数和非常函数是重载关系因为 this 类型不同可以引导说 this 是怎么来的。4.const 修饰变量时表示变量不可以修改但是可以通过指针来修改代码如下const int a 2; const int *p a; //首先将 p 从 const 类型的指针转换成非 const int* p1 const_castint*(p); //const_cast 这里可以看看 C11 的四种强制类型转换 *p1 3; cout*p *p1endl;简单来说const 修饰的变量如 const int n 0;本质上仍然是一个变量它只是被编译器在语法层面贴上了一个“只读”的标签。当你尝试直接写 a 3; 时编译器会尽职尽责地拦截并报错。但是如果你绕过编译器通过指针直接去操作这块内存*p 3;确实有有希望成功修改它。程序的运行结果完全取决于编译器的心情甚至可能直接崩溃。10.staticstatic 修饰全局变量时如果没有初始化编译器会自动初始化为 0生存周期和全局变量和程序一致只能在当前文件访问如果想在头文件中定义全局变量那么需要定义成静态全局变量因为如果多个cpp 文件引入同一个头文件那么会导致多个 cpp 文件中有相同的全局变量如果没有定义为static 会导致重定义问题。static修饰局部变量时候只做用在局部作用域只会被初始化一次不会随着函数的结束而被释放观察下面代码结果即可得知代码如下void fun() { static int a 1; a; coutaendl; } int main() { fun(); fun(); }运行结果是2 3。static int a 存储在静态存储区。它在程序启动时就被创建直到整个程序运行结束才会被销毁。static 修饰成员变量时●静态成员变量在主函数之前被初始化也就是编译期间初始化●公有的静态成员变量可以通过类名和对象名直接访问●静态成员变量不会占有对象的内存单独的存放在静态区●静态成员变量在继承关系中父类和子类共享●静态成员变量必须在类外初始化●静态成员也可以实现单例模式(可以了解下设计模式中的单例模式)static 修饰成员函数时静态成员函数没有 this 指针因此静态成员函数不能访问非静态成员变量原因无法区分是哪个对象的成员变量静态成员函数不能调用非静态成员函数因为非静态成员函数有隐含参数 this因为静态成员函数无法给非静态成员函数的 this 传值静态成员函数可以调用静态成员变量因为静态成员变量时共享的不需要使用 this 来区分是哪个对象的也可以调用静态成员函数因为静态成员函数不需要给 this 传值。这是今天所有的知识点做好查漏补缺我们明天见