c++的多态如何实现?
C++中的多态性是通过虚函数(virtual function)和虚函数表(vtable)来实现的。多态性允许在基类类型的指针或引⽤上调⽤派⽣类对象的函数,以便在运⾏时选择正确的函数实现。
- 基类声明虚函数:在基类中声明虚函数,使⽤ virtual 关键字,以便派⽣类可以重写(override)这些函数。
class Shape { public: virtual void draw() const { // 基类的默认实现 } };
- 派⽣类重写虚函数:在派⽣类中重写基类中声明的虚函数,使⽤ override 关键字。
class Circle : public Shape { public: void draw() const override { // 派⽣类的实现 } };
- 使⽤基类类型的指针或引⽤指向派⽣类对象。
Shape* shapePtr = new Circle();
- 调⽤虚函数:通过基类指针或引⽤调⽤虚函数。在运⾏时,系统会根据对象的实际类型来选择调⽤正确的函数实现。
shapePtr->draw(); // 调⽤的是 Circle 类的 draw() 函数
- 虚函数表:编译器在对象的内存布局中维护了⼀个虚函数表,其中存储了指向实际函数的指针。这个表在运⾏时⽤于动态查找调⽤的函数。
成员函数/成员变量/静态成员函数/静态成员变量的区别?
1. 成员函数
- 成员函数是属于类的函数,它们可以访问类的成员变量和其他成员函数。
- 成员函数可以分为普通成员函数和静态成员函数。
- 普通成员函数使⽤对象调⽤,可以访问对象的成员变量。
- 普通成员函数的声明和定义通常在类的内部,但定义时需要使⽤类名作为限定符。
2. 成员变量
- 成员变量是属于类的变量,存储在类的每个对象中。
- 每个对象拥有⼀份成员变量的副本,它们在对象创建时分配,并在对象销毁时释放。
- 成员变量的访问权限可以是 public 、 private 或 protected 。
class MyClass {
public:
int memberVariable; // 成员变ᰁ的声明
void memberFunction() {
// 成员函数的实现
}
};
3. 静态成员函数
- 静态成员函数属于类⽽不是对象,因此可以直接通过类名调⽤,⽽不需要创建类的实例。
- 静态成员函数不能直接访问普通成员变量,因为它们没有隐含的 this 指针。
- 静态成员函数的声明和定义也通常在类的内部,但在定义时需要使⽤类名作为限定符。
4. 静态成员变量
- 静态成员变量是属于类⽽不是对象的变量,它们在所有对象之间共享。
- 静态成员变量通常在类的声明中进⾏声明,但在类的定义外进⾏定义和初始化。
- 静态成员变量可以通过类名或对象访问。
class MyClass {
public:
static int staticMemberVariable; // 静态成员变ᰁ的声明
static void staticMemberFunction() {
// 静态成员函数的实现
}
};
int MyClass::staticMemberVariable = 0; // 静态成员变ᰁ的定义和初始化
什么是构造函数和析构函数?
1. 构造函数
构造函数是在创建对象时⾃动调⽤的特殊成员函数。它的主要⽬的是初始化对象的成员变量,为对象分配资源,执⾏必要的初始化操作。构造函数的特点包括:
- 函数名与类名相同: 构造函数的函数名必须与类名相同,且没有返回类型,包括 void。
- 可以有多个构造函数: ⼀个类可以有多个构造函数,它们可以根据参数的类型和数量不同⽽重载。
- 默认构造函数: 如果没有为类定义任何构造函数,编译器会⾃动⽣成⼀个默认构造函数。默认构造函数没有参数,也可能执⾏⼀些默认的初始化操作。
class MyClass {
public:
// 默认构造函数
MyClass() {
// 初始化操作
}
// 带参数的构造函数
MyClass(int value) {
// 根据参数进⾏初始化操作
}
};
2. 析构函数
析构函数是在对象⽣命周期结束时⾃动调⽤的特殊成员函数。它的主要⽬的是释放对象占⽤的资源、执⾏必要的清理操作。析构函数的特点包括:
- 函数名与类名相同,前⾯加上波浪号 ~ : 析构函数的函数名为 ~ClassName ,其中 ClassName 是类名。
- 没有参数: 析构函数没有参数,不能重载,每个类只能有⼀个析构函数。
- 默认析构函数: 如果没有为类定义任何析构函数,编译器会⾃动⽣成⼀个默认析构函数,执⾏简单的清理操作。
class MyClass {
public:
// 析构函数
~MyClass() {
// 清理操作,释放资源
}
};
C++构造函数有几种,分别什么作用
- 默认构造函数:没有任何参数的构造函数。如果⽤户没有为类定义构造函数,编译器会⾃动⽣成⼀个默认构造函数。默认构造函数⽤于创建对象时的初始化,当⽤户不提供初始化值时,编译器将调⽤默认构造函数。
class MyClass { public: // 默认构造函数 MyClass() { // 初始化操作 } };
- 带参数的构造函数:接受⼀个或多个参数,⽤于在创建对象时传递初始化值。可以定义多个带参数的构造函数,以⽀持不同的初始化⽅式。
class MyClass { public: // 带参数的构造函数 MyClass(int value) { // 根据参数进⾏初始化操作 } };
- 拷⻉构造函数:⽤于通过已存在的对象创建⼀个新对象,新对象是原对象的副本。参数通常是对同类型对象的引⽤。
class MyClass { public: // 拷⻉构造函数 MyClass(const MyClass &other) { // 进⾏深拷⻉或浅拷⻉,根据实际情况 } };
- 委托构造函数:在⼀个构造函数中调⽤同类的另⼀个构造函数,减少代码重复。通过成员初始化列表或构造函数体内部调⽤其他构造函数。
class MyClass { public: // 委托构造函数 MyClass() : MyClass(42) { // 委托给带参数的构造函数 } MyClass(int value) { // 进⾏初始化操作 } };