三、面向对象
约 2107 字大约 7 分钟
2026-04-28
C++构造函数有几种,分别什么作用?
- 默认构造函数
如果没有显式定义任何构造函数,编译器会自动生成一个默认构造函数。
如果定义了其他构造函数,编译器不会自动生成默认构造函数,除非显式声明 = default。
- 参数化构造函数
允许在创建对象时传入参数,直接初始化成员变量。
可以重载多个版本以适应不同的初始化需求。
- 拷贝构造函数
形式为ClassName(const ClassName& other),用于深拷贝或浅拷贝。
如果未定义,编译器会生成一个默认的拷贝构造函数(按成员浅拷贝)。
- 移动构造函数(C++11)
形式为 ClassName(ClassName&& other),用于“窃取”临时对象(右值)的资源,避免不必要的拷贝。
典型应用场景:STL容器、智能指针等需要高效资源管理的场景。
- 委托构造函数(C++11)
允许一个构造函数调用同类中的其他构造函数,避免代码重复。
示例:ClassName() : ClassName(0, 0) {}。
- 继承构造函数(C++11)
派生类通过using Base::Base直接继承基类的构造函数(C++11特性)。
注意:继承的构造函数不会初始化派生类新增的成员。
什么是构造函数和析构函数?构造函数和析构函数可以是虚函数吗?为什么?
构造函数是用于初始化对象的特殊成员函数,析构函数是对象销毁时自动调用,用于清理资源的特殊成员函数。
构造函数不能被声明为虚函数,构造期间虚表指针尚没有完全建立,而虚函数调用需要通过虚表,而构造期间这个机制不起作用。
析构函数可以声明为虚函数(特别是基类析构函数),确保通过基类指针删除派生类对象时调用正确的析构函数链,避免资源泄漏和未定义行为,如果不是虚函数,通过基类指针删除派生类对象会导致派生类部分未被正确销毁。
重载和重写,又追着问virtual 和 override的区别?
- 重载(Overload):函数名相同,参数不同,发生在同一个作用域(类内)。
即在同一个类里,函数名字一样,但参数不一样,编译器自己能分清。
- 重写(Override):派生类中重写父类的虚函数,函数名、参数、返回值完全相同,使用virtual 和 override 关键字。
virtual 是用在父类函数上,告诉编译器:“这个函数以后可能会被重写”,所以真正调用哪个版本,要在运行时决定。; override 是用在子类函数上,告诉编译器:“我就是要重写你父类的函数”。
C++怎么实现多态?
C++多态分为编译时多态和运行时多态:
编译时多态:通过函数重载和模板实现
运行时多态:通过虚函数和继承实现
虚函数表(vtable):每个包含虚函数的类都有一个虚函数表,存储虚函数地址
虚指针(vptr):每个对象包含一个指向其类虚函数表的指针
动态绑定:通过vptr在运行时确定调用哪个函数实现
C++ 中的虚函数和纯虚函数有什么区别?
虚函数(virtual function)是在基类中用virtual关键字声明的成员函数,允许派生类重写实现,实现运行时多态。
纯虚函数(pure virtual function)是在虚函数声明后加=0的函数,没有默认实现,强制派生类必须重写,并使所在类成为抽象类(不能实例化)。
通俗意义上可以这么理解:
虚函数就像是基类说"父类有这个功能,子类可以按需修改";纯虚函数则是基类说"我规定必须有这个功能,但具体怎么实现你们子类自己决定"。
虚函数怎么实现的?
第一,虚函数表(vtable):每个类有一个虚表,存储该类的虚函数地址列表。
如果某个类有虚函数,编译器就会自动生成这张表。
第二,虚指针(vptr): 每个含虚函数的类对象都有一个隐藏的成员,叫虚指针,指向当前类的虚表,这个指针用于运行时确定函数的真实调用目标。
第三,调用过程: 当通过基类指针或引用调用一个虚函数时,程序会:
先找到对象里的 vptr;
然后根据 vptr 找到对应类的 vtable;
再从 vtable 中取出正确的函数地址并调用它。
第四,动态绑定(多态): 这种通过虚表间接调用函数的方式,就是运行时多态。它让程序在运行时决定调用哪个类的函数,而不是编译时决定。
多重继承的优缺点及菱形继承问题
多重继承允许一个类同时从多个基类继承特性和行为,增强了代码复用性和表达能力。
但其主要缺点是引入名称冲突、复杂性增加和菱形继承问题。
菱形继承会导致最派生类包含多个同一基类子对象,引发二义性和数据冗余,通常需要通过虚继承来解决。
如何禁止一个类被继承
在C++中,禁止类被继承的核心方法是使用final关键字(C++11及以上标准)。
当final修饰类时,该类成为“最终类”,任何尝试继承它的派生类都会导致编译错误。
此外,C++11之前可通过基类构造函数私有化+虚继承+友元类的组合实现类似效果,但这种方式复杂且易出错,现已被final取代。
深拷贝和浅拷贝的区别?
浅拷贝(Shallow Copy)仅复制对象的成员变量值,包括指针变量的地址;
深拷贝(Deep Copy)会递归复制对象及其所有子对象,包括为指针成员分配新内存并复制内容,创建完全独立的新对象;
在C++中,当类包含指针成员时,浅拷贝会导致两个对象共享同一块内存,而深拷贝则让每个对象拥有自己独立的内存空间;
在c++中this指针的原理及存储位置
浅拷贝(Shallow Copy)仅复制对象的成员变量值,包括指针变量的地址;
深拷贝(Deep Copy)会递归复制对象及其所有子对象,包括为指针成员分配新内存并复制内容,创建完全独立的新对象;
在C++中,当类包含指针成员时,浅拷贝会导致两个对象共享同一块内存,而深拷贝则让每个对象拥有自己独立的内存空间;
C++如何实现一个单例模式?
单例模式(Singleton Pattern)确保某个类在程序运行期间只能有一个实例,并提供一个全局访问点。
常见的 C++ 实现方式:
饿汉式:程序启动时立即创建
懒汉式:第一次使用时才创建,线程不安全
双检锁(懒汉式 + 线程安全):加锁或使用 std::call_once
C++11 局部静态变量(Magic Static):推荐使用这样,因为这种情景下线程是安全的
