【C++入门】(十九)使用多态和派生类

1. 什么是虚函数成员

  1. 声明虚成员函数,使用关键字 virtual

  2. 虚成员函数的工作原理:

​ (基类和派生类在内存中相邻)

​ ① 创建后的派生类对象中包含基类部分

​ ② 指针被初始化为指向基类的虚函数成员(每个对象都有一个指向虚成员函数表的指针)

​ ③ 调用派生类的构造函数时,将调整指针,指向派生类重写的虚成员函数

​ ④ 使用基类指针时,将根据其指向的对象来指向正确的函数

  1. 不能通过基类指针访问派生类特有的方法

  2. 按值传递对象时不能调用虚成员函数,仅当通过指针和引用时才能调用虚成员函数

    void Func(Mammal MammalValue) { MammalValue.speak(); }  //Mammal speak()
    void ptrFunc(Mammal* pMammal) { pMammal->speak(); }     //speak();
    void refFunc(Mammal &rMammal) { rMammal.speak(); }      //speak();

     

2. 如何使用虚析构函数和虚复制构造函数

虚析构函数:

  1. virtual ~Mammal() { cout << "virctual ~Mammal()" << endl; }

  2. 如果类中任何一个函数是虚成员函数,那么析构函数也应该是虚成员函数

 

虚复制构造函数

  1. virtual Mammal* clone() { return new Mammal(*this); }

  2. 因为构造函数不能为虚,所以要在基类中创建一个 clone() 的虚成员函数

  

3. 虚成员函数如何让您能够多态地使用基类

  1. 声明虚成员函数 virtual void Func(){}

  2. 多态能够将派生对象视为基类对象

复制代码
#include<iostream>
using namespace std;
​
class Mammal
{
public:
    void Move() const { cout << "Mammal::Move()" << endl; }
    //virtual 虚函数
    virtual void Speak() const { cout << "Mammal::Spaek()" << endl; }
};
​
class Dog :public Mammal
{
public:
    void Move()const { cout << "Dog::Move()" << endl; }
    void Speak()const { cout << "Dog::Speak()" << endl; }
};
​
int main()
{
    //将一个新Dog对象的地址赋给Mammal指针p
    Mammal* p = new Dog;
​
    p->Move();  //Mammal::Move()
//Mammal中的Speak()是虚函数virtual,故调用Dog中重写的Speak()
    p->Speak();  //Dog::Speak()
return 0;
}
复制代码
复制代码
#include<iostream>
using namespace std;
​
class Mammal
{
public:
    //虚函数 virtual
    virtual void speak() const { cout << "Mammal::spaek()" << endl; }
};
​
class Dog :public Mammal
{
public:
    void speak()const { cout << "Dog::speak()" << endl; }
};
​
class Cat :public Mammal
{
public:
    void speak()const { cout << "Cat::speak()" << endl; }
};
​
class Pig :public Mammal
{
public:
    void speak()const { cout << "Pig::speak()" << endl; }
};
​
class Horse :public Mammal
{
public:
    void speak()const { cout << "Horse::speak()" << endl; }
};
​
int main()
{
    Mammal* array[5];
    Mammal* p;
​
    int choice;
    for (int i = 0; i < 5; i++)
    {
        cout << "1Dog,2Cat,3Horse,4Pig" << endl;
        cin >> choice;
        switch (choice)
        {
        case 1:
            p = new Dog;
            break;
        case 2:
            p = new Cat;
            break;
        case 3:
            p = new Horse;
            break;
        case 4:
            p = new Pig;
            break;
        default:
            p = new Mammal;
            break;
        }
        //将创建的对象的指针存入数组
        array[i] = p;
    }
​
    for (int i = 0; i < 5; i++)
    {
        //调用对应的speak()函数
        array[i]->speak();
    }
​
    return 0;
}
复制代码

编译阶段,无法确定调用哪个speak()函数

p指向的对象是在运行阶段确定的,这被称为 后期绑定 / 运行阶段绑定(相对于 静态绑定 / 编译阶段绑定

 

运行阶段:晚期绑定;

编译阶段:静态绑定

 

4. 使用虚成员函数的代价和风险

  1. 包含虚成员函数的类必须维护一个 v-table,因此会带来一些开销(根据 v-table ,C++知道该调用哪个虚成员函数)

  2. 如果类很小,且不打算派生出其他类,就不必要用虚成员函数

posted @   哟吼--小文文公主  阅读(100)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示