C++ 通过基类的指针或引用调用派生类的重写方法

在 C++ 中,通过 基类的指针或引用 调用派生类的重写方法,而不需要知道具体的派生类类型。


1. 为什么要用基类引用/指针调用虚函数?

C++ 的多态性允许我们使用 基类的引用或指针 来操作派生类对象,从而在运行时调用 派生类重写的虚函数,这提高了代码的可扩展性和灵活性。


2. 代码实现示例

(1)基类和派生类的关系

我们定义一个 基类 Animal,它有一个 虚函数 speak(),然后定义 两个派生类 DogCat,它们重写了 speak() 方法。

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void speak() {  // 虚函数
        cout << "Animal makes a sound!" << endl;
    }
};

class Dog : public Animal {
public:
    void speak() override {  // 重写虚函数
        cout << "Dog barks: Woof woof!" << endl;
    }
};

class Cat : public Animal {
public:
    void speak() override {  // 重写虚函数
        cout << "Cat meows: Meow meow!" << endl;
    }
};

(2)使用基类引用调用虚函数

main 函数中,我们可以创建 DogCat 的实例,但通过 基类 Animal& 的引用 来调用 speak(),这样就能在运行时调用派生类的 speak()

int main() {
    Dog myDog;
    Cat myCat;

    Animal& animalRef1 = myDog;  // 用基类引用指向派生类对象
    Animal& animalRef2 = myCat;

    animalRef1.speak();  // 调用 Dog::speak()
    animalRef2.speak();  // 调用 Cat::speak()

    return 0;
}

(3)运行结果

Dog barks: Woof woof!
Cat meows: Meow meow!

这里,animalRef1.speak() 并不会调用 Animal::speak(),而是 动态绑定Dog::speak(),因为 speak() 是虚函数。


3. 也可以使用基类指针

类似地,我们也可以使用 基类指针 而不是 引用

int main() {
    Dog myDog;
    Cat myCat;

    Animal* animalPtr1 = &myDog;  // 用基类指针指向派生类对象
    Animal* animalPtr2 = &myCat;

    animalPtr1->speak();  // 调用 Dog::speak()
    animalPtr2->speak();  // 调用 Cat::speak()

    return 0;
}

运行结果与引用的方式一致:

Dog barks: Woof woof!
Cat meows: Meow meow!

4. 关键点总结

  1. 虚函数 + 基类引用/指针 = 运行时多态

    • 只有 虚函数virtual 关键字)才能在运行时实现动态绑定,否则会调用基类的函数。
  2. 基类引用或指针指向派生类对象

    • 这样可以在 不改变代码 的情况下扩展新功能,例如新增 Bird 类,也可以直接使用 Animal& 处理,而不影响原有代码。
  3. 使用 override 关键字

    • override 可以避免函数签名错误,确保派生类确实重写了基类的虚函数。

5. 为什么不用对象本身?

如果我们直接使用 对象本身 而不是基类引用/指针,那么即使 speak() 是虚函数,也不会有动态绑定:

int main() {
    Dog myDog;
    myDog.speak();  // 直接调用 Dog::speak()

    Animal myAnimal = myDog;  // 发生了 "对象切片"(slicing),只保留基类部分
    myAnimal.speak();  // 调用的是 Animal::speak(),而不是 Dog::speak()

    return 0;
}

结果:

Dog barks: Woof woof!
Animal makes a sound!

因为 Animal myAnimal = myDog; 发生了对象切片(slicing),只保留了 Animal 的部分,所以 myAnimal.speak() 调用的是 Animal::speak(),而不是 Dog::speak()


6. 什么时候用基类引用调用虚函数?

  • 面向对象编程中的多态

    • 让代码更具扩展性,例如可以新增不同的 Animal,而不改变现有代码。
  • 接口设计

    • 例如 std::ostream&coutofstream 等类的基类,ostream& 可以调用不同的 write 方法。
  • 避免对象切片

    • 直接使用对象(值传递)可能导致对象切片,而引用/指针不会。

7. 结论

  • 虚函数让基类的引用/指针可以调用派生类的方法,实现 运行时多态
  • 如果不使用引用或指针,而是使用对象本身,会导致对象切片,失去多态性
  • 在设计模式、框架开发中,基类引用/指针调用虚函数是非常常见的模式

这样,使用 虚函数 + 基类引用/指针 可以写出更灵活、可扩展的代码!✨

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值