C++多态与虚函数

简介: C++多态与虚函数



1. 概念

1.1 多态

不同类的对象对相同的方法或函数产生有不同的反应。多态的实现依赖于虚函数

静态多态和动态多态

静态多态(编译时多态)

  1. 这是通过方法重载实现的一种多态性形式。
  2. 编译时,编译器确定使用哪个方法。重载方法的选择发生在编译阶段,因此它是静态的,编译器会确定调用哪个方法。

动态多态(运行时多态)

  1. 这是通过方法重写和继承实现的一种多态性形式。
  2. 运行时,程序确定使用哪个方法。

1.2虚函数

虚函数是指使用了修饰符virtua修饰过后的函数,而且定义虚函数的函数必须为类的成员函数,虚函数被继承后所继承的派生类都是为虚函数,析构函数可以定义为虚函数,但是构造函数(与友员函数)却不能定义为虚函数。


2. 虚函数

2.1 作用

虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在派生类中对积累定义的虚函数进行重写时,需要在派生类中声明该方法为虚方法。

2.2 析构函数可以为虚函数吗

当使用多态特性,让基类指针指向派生类对象时,如果析构函数不是虚函数,通过基类指针销毁派生类对象时,会调用静态绑定的析构函数,也就是基类的析构函数,从而只能销毁属于基类的元素,导致派生类析构不完全,程序就会出现资源泄露或未定义行为。

2.3 构造函数可以为虚函数吗

在C++中,构造函数(包括拷贝构造函数和移动构造函数)不能声明为虚函数。虚函数在运行时通过对象的虚函数表(vtable)来调用,而构造函数在对象被创建之前执行,因此在对象存在之前虚函数表也不存在,无法实现虚函数的多态性。

2.4 纯虚函数

纯虚函数必须在基类中定义,没有具体的实现代码,只有函数声明。它规定派生类必须提供该函数的具体实现。

注意:纯虚函数的类无法被实例化,只能作为基类来派生其他类。派生类必须提供对应的纯虚函数的具体实现。

示例(定义纯虚函数的语法是在函数声明后面加上 = 0):

class AbstractBase {
public:
    virtual void pureVirtualFunction1() = 0; // 第一个纯虚函数
    virtual void pureVirtualFunction2(int x) = 0; // 第二个纯虚函数带参数
    virtual void pureVirtualFunction3(double y, const std::string& str) = 0; // 第三个纯虚函数带多个参数
};
};
class Derived : public AbstractBase {
public:
    void pureVirtualFunction1() override { //override表明重写虚函数,可不加
        // 提供具体的实现
        // ...
    }
    void pureVirtualFunction2(int x) override {
        // 提供具体的实现
        // ...
    }
    void pureVirtualFunction3(double y, const std::string& str) override {
        // 提供具体的实现
        // ...
    }
};

2.5 虚表原理?虚表指针存放在哪里?

  1. 虚表的工作原理:
  • 每个包含虚函数的C++类都有一个对应的虚函数表。
  • 虚表中存储了该类中的虚函数地址。
  • 每个对象都包含一个指向其类的虚表指针。
  • 当你调用一个虚函数时,实际上是通过对象的虚表指针来查找适当的虚函数地址,然后调用该函数。
  1. 虚表指针存放在哪里:通常存放在对象内部,即对象的地址就是虚表指针的地址。

2.6 虚函数是类的定义出现还是对象的时候出现

虚函数的定义在类的定义中,而不是在创建对象时出现。

2.4 函数重载和重写区别

  1. 范围区别:重写和被重写的函数在不同的类中,重载和被重载的函数在同一类中。
  2. 参数区别:重写的函数名,参数个数,类型,顺序以及返回值类型完全一样,而重载的参数个数,类型,顺序至少有一个不同。
  3. virtual的区别:重写的基类函数必须要有virtual修饰,重载函数和被重载函数可以被virtual修饰,也可以没有

2.5 C++多态示例

#include <iostream>
using namespace std;
class Shape {
public:
    virtual double area() const = 0; // 纯虚函数
};
class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const {
        return 3.14159265359 * radius * radius;
    }
};
class Rectangle : public Shape {
private:
    double width;
    double height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double area() const {
        return width * height;
    }
};
int main() {
    Circle circle(5.0);
    Rectangle rectangle(4.0, 6.0);
    Shape* shape1 = &circle;
    Shape* shape2 = &rectangle;
    std::cout << "面积1: " << shape1->area() << std::endl;
    std::cout << "面积2: " << shape2->area() << std::endl;
    return 0;
}

致读者

非知之难,行之为难;非行之难,终之斯难

目录
相关文章
|
25天前
|
C++
9. C++虚函数与多态
9. C++虚函数与多态
26 0
|
1月前
|
算法 安全 编译器
【C++ 关键字 override】C++ 重写关键字override(强制编译器检查该函数是否覆盖已存在的虚函数)
【C++ 关键字 override】C++ 重写关键字override(强制编译器检查该函数是否覆盖已存在的虚函数)
27 0
|
1月前
|
算法 Java 编译器
【C++ 关键字 virtual 】C++ virtual 关键字(将成员函数声明为虚函数实现多态
【C++ 关键字 virtual 】C++ virtual 关键字(将成员函数声明为虚函数实现多态
25 0
|
1天前
|
编译器 C++
c++的学习之路:23、多态(2)
c++的学习之路:23、多态(2)
6 0
|
26天前
|
编译器 C++
C++之多态
C++之多态
|
27天前
|
存储 程序员 编译器
【C++ 模板类与虚函数】解析C++中的多态与泛型
【C++ 模板类与虚函数】解析C++中的多态与泛型
46 0
|
28天前
|
设计模式 存储 安全
【C++ 基本概念】C++编程三剑客:模板、多态与泛型编程的交织与差异
【C++ 基本概念】C++编程三剑客:模板、多态与泛型编程的交织与差异
102 0
|
29天前
|
存储 安全 算法
【C++ 17 包裹类 泛型容器 std::any】深入理解与应用C++ std::any:从泛型编程到多态设计
【C++ 17 包裹类 泛型容器 std::any】深入理解与应用C++ std::any:从泛型编程到多态设计
48 1
|
1月前
|
存储 算法 编译器
【C++ 模板应用】模板哪些行为属于多态哪些行为属于泛型编程?
【C++ 模板应用】模板哪些行为属于多态哪些行为属于泛型编程?
25 0
|
1月前
|
存储 安全 编译器
【C++ 多态 】深入理解C++的运行时类型信息(RTTI):dynamic_cast和typeid的应用与原理
【C++ 多态 】深入理解C++的运行时类型信息(RTTI):dynamic_cast和typeid的应用与原理
51 1

热门文章

最新文章