1. 类与对象的基本概念
- 什么是类,什么是对象?(用自己的话描述)
- 类(Class):是一个蓝图、模板或自定义的数据类型。它定义了某类事物共有的属性(成员变量)和行为(成员函数)。它本身不占用实际的内存空间(除了类型信息)。
- 对象(Object):是类的一个具体实例。根据类这个模板在内存中实际分配了空间,拥有具体的属性值。比如“人”是类,而“张三”是一个对象。
2. 权限修饰符
- public的权限是什么? 公开的。类内部可以访问,类外部(通过对象)也可以直接访问。通常用于提供对外接口。
- private的权限是什么? 私有的。只能在类的内部(成员函数中)或者友元中被访问。类外部无法直接访问,通常用于隐藏数据(封装)。
(补充:还有一个protected,权限介于两者之间,类外部不能访问,但子类可以访问)
3. struct 与 class 的区别
- 在C++中,两者区别很小,主要在于默认的访问权限和默认的继承权限:
struct的默认访问权限和默认继承权限是public。class的默认访问权限和默认继承权限是private。
4. 构造函数 (Constructor)
- 什么是构造函数?有什么作用? 函数名与类名相同,且没有返回类型(连void都没有)的特殊成员函数。作用是初始化对象的数据成员,分配资源等。
- 什么时候会调用构造函数? 在创建对象时自动调用。包括:栈上创建对象、堆上
new对象、创建临时对象、以及作为成员对象被包含在另一个类中初始化时。
5. 对象的大小
- 一个对象的大小取决于什么? 取决于:
- 非静态成员变量的总大小(受内存对齐影响,可能会有padding填充)。
- 如果有虚函数,需要加上一个虚函数表指针(vptr)的大小(通常为8字节或4字节)。
- 注意:静态成员变量、成员函数、虚函数表本身不占用对象的内存空间。空类的大小通常为1字节。
6. 左值与右值
- 什么是左值?什么是右值?
- 左值(L-value):有明确的内存地址,有名字,表达式结束后依然存在的持久对象(如变量、数组元素、解引用的指针)。
- 右值(R-value):没有名字,临时存在的值,表达式结束后就销毁(如字面量、临时对象、返回非引用类型的函数返回值)。
- 什么样的引用可以绑定左值? 非常量左值引用(
T&)只能绑定左值;常量左值引用(const T&)可以绑定左值(也是万能引用的一种形式)。 - 什么样的引用可以绑定左值和右值? **常量左值引用(
const T&)既可以绑定左值,也可以绑定右值。
*(补充:C++11引入的右值引用(T&&)*只能绑定右值)
7. 拷贝构造函数
- 语法形式是什么?为什么? 形式:
ClassName(const ClassName& other)。必须是引用传参,因为如果按值传参,实参传给形参时会再次调用拷贝构造,导致无限递归死循环。加const是为了能接收常量对象和临时对象。 - 什么情况下会触发拷贝构造的调用?
- 用一个已存在的对象初始化新对象(
A a = b;或A a(b);)。 - 对象作为实参,以值传递的方式传给函数。
- 函数返回局部对象(以值方式返回,取决于编译器优化,未优化时会触发)。
- 用一个已存在的对象初始化新对象(
8. 深拷贝与浅拷贝
- 什么是深拷贝,什么是浅拷贝?
- 浅拷贝:仅仅复制对象的所有成员变量的值(如果是指针,就只复制指针地址)。这会导致两个对象共享同一块堆内存,容易引发“双重释放(Double Free)”问题。默认生成的拷贝构造函数就是浅拷贝。
- 深拷贝:在复制指针成员时,不是复制地址,而是重新在堆区分配一块新的内存,并将原指针指向的内容复制过去。这样两个对象各自拥有独立的资源,互不影响。
9. 析构函数 (Destructor)
- 语法形式是什么?
~ClassName(),没有参数,没有返回值,不能重载,一个类只能有一个析构函数。 - 析构函数一般用来干什么? 在对象生命周期结束时自动调用。主要用于清理资源,比如释放动态分配的堆内存(
delete)、关闭文件句柄、释放网络连接等,防止内存泄漏。
10. this 指针
- this是什么?this的本质是什么?
this是当前对象的指针。- 它的本质是一个隐含的形参(编译器自动添加的),指向调用该成员函数的对象。在底层,它是
ClassName* const this(一个指针常量,即指向不能改变,但指向的内容可以改变)。静态成员函数没有this指针。
11. 赋值运算符重载函数
- 语法形式是什么?为什么?
ClassName& operator=(const ClassName& other)。- 为什么返回引用
ClassName&? 为了支持链式赋值(如a = b = c),并且避免返回时调用一次拷贝构造。 - 为什么参数是
const ClassName&? 防止在赋值过程中修改原对象(const),且引用传参避免一次拷贝(&)。
- 为什么返回引用
- 赋值运算符函数的本质是什么? 是对已存在的两个对象进行数据成员的覆盖和资源的重新分配。它与拷贝构造的区别在于:拷贝构造是在对象初始化时调用,而赋值运算符是在对象已经存在时调用。
(注意点:在实现赋值运算符时,必须检查自我赋值if (this != &other),并且如果是深拷贝,需要先释放原有的资源,再分配新资源)。
这份提纲涵盖了C++面向对象编程最核心的基础知识点,非常适合用来准备面试或期末复习。如果有哪一部分需要更深入的原理解析(比如汇编层面的this传递或虚函数表),可以继续提问。