STATUS: NOMINAL LOCAL TIME: 00:00:00 返回园内

[C++]多态与虚函数

[C++]多态与虚函数

多态

多态的字面意思是,具有多种形态,体现在程序中就是:同一个函数的行为随上下文而异。C++通过静态绑定和动态绑定实现多态。
其中,静态绑定是在编译时就确定了要调用的函数,编译器会根据函数名和参数来决定,但是对于虚函数,只能在程序运行时进行选择。
对于面向对象中的多态性,一般只考虑动态绑定,C++通过虚函数来实现。

虚函数

在类中声明一个虚函数,使用关键字“virtual”,使得子类可以重写(override)这个函数:

class Person
{
protected:
    string name;
public:
    Person(string n) : name(n) {}
    virtual void Say()
    {
        cout << "I'm a person.\n";
    };
};

class Student : Person
{
public:
    int id;
    Student(string n, int i) : public Person(n), id(i) {}
    void Say() override
    {
        cout << "I'm a student.\n";
    };
};

当然,也可以声明纯虚函数,此时该类为抽象类,不能被实例化

virtual void f() = 0;

构造函数不能是虚函数;析构函数应该是虚函数,通常应给基类提供一个虚析构函数,即使它并不需要析构函数。

向上类型转换(upcasting)

C++一般不允许将A类的地址赋值给B类指针,也不允许不同类型间的引用。但对于继承关系,C++的指针和引用运行父类指针指向子类对象,而不需要作显式类型转换:

Student s("Alice", 1);
Person *p = &s;
Person &r = s;

这被称为向上类型转换(upcasting),而将子类指针指向父类地址,则是向下类型转换,显然需要显示类型转换:

Student* ps = static_cast<Student*>(&p1);

有了upcasting,就需要在运行时确定类型。

虚函数表

编译器处理虚函数时,会为类型添加一个隐藏的成员数组,称为虚函数表(virtual function table,vtbl),而虚函数表中存储了声明的所有虚函数的地址。
如果子类override了父类的一个虚函数,那么它的地址就是新的,否则就跟父类中的地址一样。
调用虚函数时,程序将查看存储在对象中的vtbl地址,然后转向相应的函数地址表,找到对应的地址,并执行具有该地址的函数。
可以参考图片:
1774948795391.png

posted @ 2026-03-31 17:21  猫爹爱猫娘  阅读(3)  评论(0)    收藏  举报