C++虚函数

一、虚函数的定义

虚函数就是在基类中被关键字virtual说明,并且在派生类中重新定义的函数。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

在基类中的某个成员函数被声明为虚函数后。此虚函数就可以在一个或多个派生类中被重新定义。在派生类中重新定义时,其函数原型,包括函数类型、函数名、参数个数、参数类型的顺序,都必须与基类中的原型完全相同。

声明虚函数

虚函数的声明形式与普通成员函数类似,但在基类中需要加上 virtual 关键字。派生类中可以重写这个虚函数(重写时可以加上 override 关键字进行显式标注,但不是必须的)。

virtual 函数类型 函数名(形参表)

{

       函数体

}

二、虚函数示例

虚函数声明

首先,我们定义一个基类 Animal,其中包含一个虚函数 makeSound

#include <iostream>

// 基类 Animal
class Animal {
public:
    // 虚函数 makeSound
    virtual void makeSound() const {
        std::cout << "Some generic animal sound" << std::endl;
    }

    // 虚析构函数
    virtual ~Animal() {
        std::cout << "Animal destructor called" << std::endl;
    }
};
派生类中重写虚函数

接下来,我们定义两个派生类 DogCat,它们重写基类中的虚函数 makeSound

// 派生类 Dog
class Dog : public Animal {
public:
    // 重写 makeSound 函数
    void makeSound() const override {
        std::cout << "Woof" << std::endl;
    }

    ~Dog() override {
        std::cout << "Dog destructor called" << std::endl;
    }
};

// 派生类 Cat
class Cat : public Animal {
public:
    // 重写 makeSound 函数
    void makeSound() const override {
        std::cout << "Meow" << std::endl;
    }

    ~Cat() override {
        std::cout << "Cat destructor called" << std::endl;
    }
};
使用虚函数

现在我们编写主程序,展示如何使用基类指针和引用调用虚函数。基类指针法:

int main() {
    // 创建具体的形状对象
    Animal* animal1 = new Dog();
    Animal* animal2 = new Cat();

    // 通过基类指针调用虚函数
    animal1->makeSound();  // 输出: Woof
    animal2->makeSound();  // 输出: Meow

    // 确保调用派生类的析构函数
    delete animal1;  // 输出: Dog destructor called
                     //      Animal destructor called
    delete animal2;  // 输出: Cat destructor called
                     //      Animal destructor called

    return 0;
}

基类引用法

#include <iostream>
using namespace std;

// 基类 Animal
class Animal {
public:
    // 虚函数 makeSound,基类中提供通用接口
    virtual void makeSound() const {
        cout << "Some generic animal sound" << endl;
    }

    // 虚析构函数,确保正确调用派生类的析构函数
    virtual ~Animal() {}
};

// 派生类 Dog,继承自 Animal
class Dog : public Animal {
public:
    // 重写 makeSound 方法
    void makeSound() const override {
        cout << "Woof! Woof!" << endl;
    }
};

// 派生类 Cat,继承自 Animal
class Cat : public Animal {
public:
    // 重写 makeSound 方法
    void makeSound() const override {
        cout << "Meow! Meow!" << endl;
    }
};

// 函数展示动物叫声,使用基类引用
void showAnimalSound(const Animal& animal) {
    animal.makeSound();
}

int main() {
    // 创建基类和派生类对象
    Animal genericAnimal;
    Dog dog;
    Cat cat;

    // 使用基类引用调用虚函数,展示多态性
    showAnimalSound(genericAnimal);  // 输出 "Some generic animal sound"
    showAnimalSound(dog);            // 输出 "Woof! Woof!"
    showAnimalSound(cat);            // 输出 "Meow! Meow!"

    return 0;
}

三、虚函数与重载函数的关系

虚函数是用于实现运行时多态性的。通过在基类中声明虚函数,派生类可以重写这些虚函数,从而在运行时根据实际对象类型调用相应的函数实现。这种机制依赖于动态绑定(动态调度),即在运行时决定调用哪一个版本的函数。

虚函数特点
  • 定义:在基类中用 virtual 关键字声明。
  • 用途:实现运行时多态性。
  • 动态绑定:函数调用在运行时进行解析。
  • 重写:派生类可以重写基类中的虚函数。
示例
#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() const {
        cout << "Base show" << endl;
    }
    virtual ~Base() {}
};

class Derived : public Base {
public:
    void show() const override {
        cout << "Derived show" << endl;
    }
};

void display(const Base& obj) {
    obj.show(); // 调用的是具体对象的 show() 方法
}

int main() {
    Base b;
    Derived d;

    display(b);  // 输出 "Base show"
    display(d);  // 输出 "Derived show"

    return 0;
}
重载函数

重载函数是指在同一个作用域中,函数名相同但参数列表不同的多个函数。编译器根据调用时的参数列表决定调用哪个函数版本。这是一种编译时的多态性(静态多态性)。

特点
  • 定义:同名函数在同一作用域中具有不同的参数列表。
  • 用途:实现编译时多态性,提高函数的可读性和可用性。
  • 静态绑定:函数调用在编译时进行解析。
  • 参数列表:必须不同(参数类型、个数或顺序不同)。
示例
#include <iostream>
using namespace std;

class Printer {
public:
    void print(int i) {
        cout << "Printing int: " << i << endl;
    }

    void print(double f) {
        cout << "Printing float: " << f << endl;
    }

    void print(const char* c) {
        cout << "Printing string: " << c << endl;
    }
};

int main() {
    Printer p;
    p.print(10);           // 调用 void print(int)
    p.print(5.5);          // 调用 void print(double)
    p.print("Hello");      // 调用 void print(const char*)

    return 0;
}

小结:虚函数的动态绑定是通过虚函数表和虚函数指针实现的,使得程序在运行时能够根据实际对象类型调用正确的虚函数版本。动态绑定是实现多态性的关键机制,使得代码更加灵活和可扩展,能够处理不同类型的对象而无需在编译时知道具体的对象类型。 

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值