C++:函数重载和函数重写

目录

函数重载和函数重写

静态绑定和动态绑定

虚函数表

虚函数和纯虚函数

什么函数不能声明为虚函数? 


函数重载和函数重写

函数重载

函数重写

函数重载是指在同一个作用域内,可以有多个函数名相同但参数列表不同的函数。

函数重写是指在派生类中重新定义基类中已经存在的函数,且函数名、参数列表和返回类型都相同。

特点:

  1. 函数重载通过函数名和参数列表的不同来区分不同的函数。
  2. 重载函数可以具有不同的返回类型,但不能仅通过返回类型的不同来进行重载。
  3. 重载函数可以有不同的参数个数、不同的参数类型或不同的参数顺序
  4. 函数重载在编译时通过静态多态性(静态绑定)实现,即根据函数调用时所传递的参数类型来决定调用哪个重载函数。

特点:

  1. 函数重写通过派生类中的函数重新实现基类中的同名函数。
  2. 函数重写必须具有相同的函数签名(函数名、参数列表和返回类型)。
  3. 函数重写在运行时通过动态多态性(动态绑定)实现,即根据对象的实际类型来决定调用哪个重写函数。
//函数重载
#include 
using namespace std;
class Calculator {
public:
    int add(int a, int b) {
        return a + b;
    }
    
    double add(double a, double b) {
        return a + b;
    }
};

int main() {
    Calculator calculator;
    
    int result1 = calculator.add(5, 3);             // 调用 int add(int a, int b)
    double result2 = calculator.add(2.5, 3.7);      // 调用 double add(double a, double b)
    
    cout << "Result 1: " << result1 << endl;
    cout << "Result 2: " << result2 << endl;
    
    return 0;
}
//函数重写
#include 
using namespace std;
// 基类 Animal
class Animal {
public:
    virtual void makeSound() {
        cout << "The animal makes a sound." << endl;
    }
};

// 派生类 Dog
class Dog : public Animal {
public:
    void makeSound() override {
        cout << "The dog barks." << endl;
    }
};

// 派生类 Cat
class Cat : public Animal {
public:
    void makeSound() override {
        cout << "The cat meows." << endl;
    }
};

int main() {
    // 创建 Animal 类的实例,并调用 makeSound 方法
    Animal* animal = new Animal();
    animal->makeSound();  // 输出: The animal makes a sound.

    // 创建 Dog 类的实例,并调用 makeSound 方法
    Dog* dog = new Dog();
    dog->makeSound();  // 输出: The dog barks.

    // 创建 Cat 类的实例,并调用 makeSound 方法
    Cat* cat = new Cat();
    cat->makeSound();  // 输出: The cat meows.

    // 使用基类指针指向派生类对象,并调用 makeSound 方法
    Animal* animalPtr = dog;
    animalPtr->makeSound();  // 输出: The dog barks.

    animalPtr = cat;
    animalPtr->makeSound();  // 输出: The cat meows.

    delete animal;
    delete dog;
    delete cat;

    return 0;
}

静态绑定和动态绑定

静态绑定(静态多态性)

动态绑定(动态多态性)

静态绑定在编译时确定调用哪个函数,根据变量的静态类型进行匹配。

动态绑定在运行时确定调用哪个函数,根据变量的实际类型进行动态选择。

静态绑定是通过函数名和参数类型的匹配来实现的。

动态绑定是通过虚函数表(vtable虚函数指针(vpointer来实现的。允许在派生类中重写基类的虚函数并实现多态性。

静态绑定适用于非虚函数和静态成员函数。

动态绑定适用于虚函数虚基类的成员函数。

虚函数表

        虚函数表(Virtual Function Table,简称VTable)是用于实现C++中动态多态(即运行时多态)的一种机制。它是一种存储虚函数指针的数据结构,用于支持基类和派生类之间的动态绑定。

        在C++中,当一个类中声明了虚函数时,编译器会为该类生成一个虚函数表。虚函数表是一个数组,每个元素存储着一个指向相应虚函数的指针。对于含有虚函数的类,编译器会在该类的对象中插入一个指向虚函数表的指针(通常称为虚函数表指针或虚指针)。这个指针指向了该类的虚函数表。

        当通过基类指针或引用调用一个虚函数时,C++会根据对象的实际类型(而不是指针或引用的类型)来确定要调用的函数。通过虚函数表的指针,C++可以在运行时动态地查找正确的函数并进行调用。

#include 
using namespace std;
class Animal {
public:
    void makeSound() {
        cout << "动物发出声音" << endl;
    }
    virtual void eat() {
        cout << "动物正在吃东西" << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() {
        cout << "狗发出汪汪的声音" << endl;
    }
    void eat() override {
        cout << "狗正在吃骨头" << endl;
    }
};
int main() {
    Animal* animal1 = new Animal();
    Animal* animal2 = new Dog();
    //
    animal1->makeSound(); // 静态绑定,输出: 动物发出声音
    animal2->makeSound(); // 静态绑定,输出: 动物发出声音

    animal1->eat(); // 动态绑定,输出: 动物正在吃东西
    animal2->eat(); // 动态绑定,输出: 狗正在吃骨头

    delete animal1;
    delete animal2;
    return 0;
}

        在上述代码中,makeSound() 函数在基类 Animal 中被声明为普通成员函数,并没有使用 virtual 关键字。这意味着它不是一个虚函数,因此不会进行动态绑定。即使在 Dog 类中使用 makeSound() 的重定义,也不会产生多态效果。 

        const关键字

        关键字在 C++ 中用于指定变量或函数的不可修改性。可以在编译时进行静态绑定。

虚函数和纯虚函数

虚函数

纯虚函数

虚函数是在基类中声明的成员函数,用关键字"virtual"进行修饰。

纯虚函数是在基类中声明的虚函数,但没有提供实现,通过在函数声明末尾加上 "= 0" 来指定它为纯虚函数。

派生类可以重写虚函数,即在派生类中重新定义和实现基类的虚函数。

带有纯虚函数的类被称为抽象类,不能直接实例化抽象类的对象。(但可以通过指针或引用来访问抽象类的派生类对象。

在运行时,通过指向派生类对象的基类指针或引用调用虚函数时,将根据对象的实际类型调用相应的函数。

派生类必须实现基类中的纯虚函数,才能实例化派生类的对象。

虚函数允许基类指针或引用在运行时动态地确定所调用的函数版本。

纯虚函数为派生类提供了一个必须实现的接口,但具体的实现方式可以因派生类而异。

虚函数可以有实现(非纯虚函数)也可以没有实现(纯虚函数)。

如果派生类没有实现基类的纯虚函数,那么派生类仍然是抽象类。

虚函数和纯虚函数都用于实现多态性和继承机制。

总而言之,虚函数提供了一种默认的实现,允许派生类进行覆盖,而纯虚函数则强制要求派生类提供自己的实现。

什么函数不能声明为虚函数? 

  1. 静态函数(static function):静态函数属于类而不是类的实例,因此不能用于多态。虚函数的主要目的是实现运行时的多态性,而静态函数与特定类的实例无关。
  2. 构造函数:构造函数没有继承的概念,因此不能被声明为虚函数。此外,虚函数需要在对象完全构造之后才能调用,但构造函数的目的就是创建对象,因此不适合作为虚函数。
  3. 内联函数(inline function):内联函数是在调用点进行代码展开的函数,它通常在编译时进行展开,不会进行函数调用。虚函数的实现涉及虚函数表等机制,不适合用于内联函数。
  4. 友元函数(friend function):友元函数是在类外部定义的(类内声明),但具有对类的私有成员的访问权限。由于友元函数不是类的成员函数,它不能被声明为虚函数。

你可能感兴趣的:(C++,c++,开发语言)