C++虚函数、纯虚函数、抽象类和多态介绍

C++虚函数、纯虚函数、抽象类和多态介绍

C++虚函数、纯虚函数

虚函数(Virtual Function):

虚函数是在基类中声明为虚函数的成员函数。通过使用虚函数,可以在派生类中重新定义该函数,实现运行时的动态绑定。当通过基类指针或引用调用一个虚函数时,实际上会根据指针或引用所指向的对象的类型来决定调用哪个类的版本。

在基类中将函数声明为虚函数的语法如下:

virtual返回类型 函数名 (参数表) {

    // 函数体

}

虚函数声明中含有virtual

当我们在C++中使用虚函数时,通常会创建一个基类(父类)和一个或多个派生类(子类)。下面是一个完整的示例,展示了如何使用虚函数:

#include <iostream>
using namespace std; 

// 基类 Animal
class Animal {
public:
    virtual void makeSound() {
        cout << "动物发出声音" << endl;
    }
};

// 派生类 Dog
class Dog : public Animal {
public:
    void makeSound() override {
        cout << "汪汪!" << endl;
    }
};

// 派生类 Cat
class Cat : public Animal {
public:
    void makeSound() override {
        cout << "喵喵!" << endl;
    }
};

int main() {
    Animal* animalPtr;

    // 创建一个 Dog 对象,并将其地址赋值给基类指针
    animalPtr = new Dog();
    animalPtr->makeSound(); // 调用 Dog 类中重写的 makeSound 函数

    // 创建一个 Cat 对象,并将其地址赋值给基类指针
    animalPtr = new Cat();
    animalPtr->makeSound(); // 调用 Cat 类中重写的 makeSound 函数

    delete animalPtr; // 释放内存

    return 0;
}

示例中,定义了一个基类 Animal 和两个派生类 Dog 和 Cat。Animal 类中的 makeSound 函数被声明为虚函数,在派生类中进行了重写。

扫描二维码关注公众号,回复: 15905977 查看本文章

在主函数中,首先创建一个基类指针 animalPtr,然后将其分别指向 Dog 和 Cat 对象。通过基类指针调用 makeSound 函数时,实际上会根据对象的类型调用相应的派生类中的重写函数。

纯虚函数(Pure Virtual Function):

纯虚函数是在基类中声明为纯虚函数的成员函数,它只有函数的声明而没有函数的定义。纯虚函数在基类中没有默认实现,派生类必须给出自己的实现。基类中含有纯虚函数的类被称为抽象类,抽象类不能被实例化,只能作为基类被继承。

在基类中将函数声明为纯虚函数的语法如下:

virtual 返回类型 函数名 (参数表) = 0;

纯虚函数声明中含有virtual和= 0

当我们想要在C++中创建一个抽象基类(Abstract Base Class)时,可以使用纯虚函数。纯虚函数是没有实际定义的虚函数,它们只用于提供接口,并且必须在派生类中实现。下面是一个完整的示例,展示了如何使用纯虚函数:

#include <iostream>
using namespace std; 

// 抽象基类 Animal
class Animal {
public:
    virtual void makeSound() = 0; // 纯虚函数,没有实际定义
};

// 派生类 Dog
class Dog : public Animal {
public:
    void makeSound() override {
        cout << "汪汪!" << endl;
    }
};

// 派生类 Cat
class Cat : public Animal {
public:
    void makeSound() override {
        cout << "喵喵!" << endl;
    }
};

int main() {
    Animal* animalPtr;

    // 创建一个 Dog 对象,并将其地址赋值给基类指针
    animalPtr = new Dog();
    animalPtr->makeSound(); // 调用 Dog 类中实现的 makeSound 函数

    // 创建一个 Cat 对象,并将其地址赋值给基类指针
    animalPtr = new Cat();
    animalPtr->makeSound(); // 调用 Cat 类中实现的 makeSound 函数

    delete animalPtr; // 释放内存

    return 0;
}

示例中,定义了一个抽象基类 Animal,其中包含一个纯虚函数 makeSound。派生类 Dog 和 Cat 必须实现这个纯虚函数,否则它们自己也会成为抽象类。

在主函数中,首先创建一个基类指针 animalPtr,然后将其分别指向 Dog 和 Cat 对象。通过基类指针调用 makeSound 函数时,实际上会根据对象的类型调用相应的派生类中实现的函数。

C++中的虚函数和纯虚函数是面向对象编程中的重要概念。它们用于实现多态性和基类与派生类的关系。下面是一个同时使用虚函数和纯虚函数的示例:

#include <iostream>
using namespace std;

// 基类 Animal
class Animal {
public:
    // 虚函数,可以被派生类重新定义
    virtual void makeSound() {
        cout << "Animal makes sound" << endl;
    }

    // 纯虚函数,必须在派生类中实现
    virtual void showInfo() = 0;
};

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

    void showInfo() override {
        cout << "I am a dog" << endl;
    }
};

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

    void showInfo() override {
        cout << "I am a cat" << endl;
    }
};

int main() {
    Animal* animalPtr;

    Dog dog;
    Cat cat;

    animalPtr = &dog;
    animalPtr->makeSound();  // 输出:Dog barks
    animalPtr->showInfo();   // 输出:I am a dog

    animalPtr = &cat;
    animalPtr->makeSound();  // 输出:Cat meows
    animalPtr->showInfo();   // 输出:I am a cat

    return 0;
}

在上述示例中,我们定义了一个基类 Animal,其中包含一个虚函数 makeSound() 和一个纯虚函数 showInfo()。派生类 Dog 和 Cat 分别继承自基类 Animal 并重写这两个函数。

在 main 函数中,我们使用基类指针 animalPtr 分别指向 Dog 对象和 Cat 对象,并通过调用虚函数来实现多态性。无论 animalPtr 指向哪个对象,它都能够根据对象的实际类型来调用相应的函数。

运行上述示例,输出结果如下:

Dog barks
I am a dog
Cat meows
I am a cat

通过使用虚函数和纯虚函数,我们可以根据对象的实际类型来调用对应的函数,实现了多态性的效果。

抽象类(Abstract Classes

在C++中,含有纯虚函数的类称之为抽象类。抽象类是一种特殊的类,不能直接实例化对象。抽象类用于定义接口和共享功能,并要求派生类实现特定的方法。

为了将一个类定义为抽象类,可以在类中声明一个或多个纯虚函数(Pure Virtual Function)。纯虚函数是在基类中声明但没有实现的虚函数,通过使用 "= 0" 来指定。

抽象类充当了一种规范或接口,它提供了一组公共的方法(包括纯虚函数),派生类必须实现这些方法才能被实例化。抽象类可以派生出其他具体的类,这些派生类必须实现基类中的纯虚函数。

以下是一个示例代码:

#include <iostream>
using namespace std;

// Abstract class
class AbstractClass {
public:
    // Pure virtual function
    virtual void pureVirtualFunction() = 0;

    // Normal member function:普通成员函数
    void normalFunction() {
        cout << "这是一个普通函数。" << endl;
    }
};

// Concrete class inheriting from AbstractClass:继承自抽象类的具体类
class ConcreteClass : public AbstractClass {
public:
    void pureVirtualFunction() override {
        cout << "这是纯虚函数的实现。" << endl;
    }
};

int main() {
    // Creating an object of ConcreteClass
    ConcreteClass concreteObj;

    // Calling member functions
    concreteObj.pureVirtualFunction();
    concreteObj.normalFunction();

    return 0;
}

在这个示例中,我们定义了一个名为AbstractClass的抽象类,其中包含了一个纯虚函数pureVirtualFunction()和一个普通成员函数normalFunction()。纯虚函数没有具体的实现,表明它必须在派生类中被重写。

ConcreteClass是一个继承自AbstractClass的具体类,它提供了对纯虚函数的实现。

在main()函数中,我们创建了一个ConcreteClass的对象,并调用了纯虚函数和普通函数。

程序运行输出结果为::

这是纯虚函数的实现。
这是一个普通函数。

C++多态(polymorphism

C++多态,简单说是指不同继承关系的类对象去调用同一函数时,产生了不同的行为。

多态是面向对象编程中的一个重要概念。

C++中的多态(polymorphism)是指通过基类的指针或引用调用派生类的成员函数(方法),并根据对象的实际类型来执行不同的成员函数(方法)。

在C++中多态性有两种形式:静态多态性(static polymorphism)和动态多态性(dynamic polymorphism)。

在C++中,重写(override)和重载(overload)都能够帮助程序员实现多态性。

重写是指在派生类中重新定义与基类中具有相同名称和参数列表的函数。通过重写,派生类可以重定义基类中已经存在的函数,使用新的实现方法。这样,当通过基类的指针或引用调用该函数时,实际执行的是派生类中的版本。

重载则是指在同一个作用域内定义多个具有相同名称但参数列表不同的函数。重载允许使用相同的函数名来表示不同的行为。

C++中重写(override)和重载(overload),可参见https://blog.csdn.net/cnds123/article/details/131653045

多态的关键概念包括:

虚函数(virtual function):在基类中声明的可以被派生类重写的函数。使用virtual关键字进行标识。

动态多态性(dynamic polymorphism)和静态多态性(static polymorphism):

动态多态性是在运行时确定函数的调用,也称为运行时多态性或动态绑定(dynamic binding)。它通过使用虚函数和动态绑定来实现。当通过基类指针或引用调用一个虚函数时,实际上会根据对象的类型在运行时选择调用哪个函数。这种方式在运行时才能确定函数的具体实现。

静态多态性是在编译时确定函数的调用,也称为编译时多态性。它通过使用函数重载和函数模板来实现。编译器根据函数调用时传入的参数类型来选择调用合适的函数。这种方式在编译时就能确定函数的具体实现。

向上转型(upcasting):将派生类对象赋值给基类指针或引用的过程。通过向上转型,可以将派生类对象当作基类对象来对待。

重写(overriding):在派生类中重新定义并实现基类中声明为虚函数的函数。重写取代了基类中的函数实现。

C++中主要的多态实现方式:

1.通过虚函数(virtual function)和动态绑定(dynamic binding)来实现多态。在基类中将需要重写的函数声明为虚函数,在派生类中进行重写,并使用override关键字确保正确继承。通过基类指针或引用指向派生类对象时,调用的是派生类中的函数。这种方式称为动态多态性,因为调用的函数是根据实际对象的类型在运行时决定的。

通过虚函数和动态绑定实现多态示例:

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void makeSound() {
        cout << "Animal is making a sound." << endl;
    }
};

class Dog : public Animal {
public:
    void makeSound() override {
        cout << "Dog is barking." << endl;
    }
};

int main() {
    Animal* animal = new Animal();
    Dog* dog = new Dog();

    animal->makeSound(); // 输出:"Animal is making a sound."
    dog->makeSound();    // 输出:"Dog is barking."

    Animal* ptr = dog;
    ptr->makeSound();    // 输出:"Dog is barking."

    delete dog;
    delete animal;
    return 0;
}

2.使用纯虚函数(pure virtual function)和抽象基类(abstract base class)来实现纯虚函数。纯虚函数在基类中没有实际的定义,派生类必须重写该函数才能实例化。抽象基类不能被实例化,只能作为接口使用。为动态多态性。

使用纯虚函数和抽象基类实现多态示例:

#include <iostream>
using namespace std;

class Shape {
public:
    virtual double calculateArea() const = 0; // 纯虚函数
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double calculateArea() const override {
        return 3.14 * radius * radius;
    }
};

int main() {
    Circle circle(5);
    Shape* shape = &circle;

    cout << "Area of the circle: " << shape->calculateArea() << endl; // 输出:Area of the circle: 78.5

    return 0;
}

3.通过函数重载(function overloading)来实现静态多态。函数重载允许在同一作用域中定义多个同名函数,但参数类型、参数个数或参数顺序不同。编译器根据实参的类型选择调用合适的函数。这种方式称为静态多态性,因为在编译时就确定了要调用哪个函数。

通过函数重载实现多态示例:

#include <iostream>
using namespace std;

void printNumber(int num) {
    cout << "Integer number: " << num << endl;
}

void printNumber(double num) {
    cout << "Floating-point number: " << num << endl;
}

int main() {
    int i = 10;
    double d = 3.14;

    printNumber(i); // 输出:"Integer number: 10"
    printNumber(d); // 输出:"Floating-point number: 3.14"

    return 0;
}

4.函数模板(function templates):通过使用模板参数来接受不同类型的参数,从而实现静态多态。编译器会根据调用时传入的参数类型自动生成适合的函数。

通过函数模板实现多态示例:

#include <iostream>
using namespace std;

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    int i1 = 5, i2 = 10;
    double d1 = 3.14, d2 = 2.71;

    cout << "Maximum of two integers: " << maximum(i1, i2) << endl;       // 输出:10
    cout << "Maximum of two floating-point numbers: " << maximum(d1, d2) << endl; // 输出:3.14

    return 0;
}

上述提到的是C++中主要的多态实现方式。

附录

C++ 虚函数、纯虚函数https://zhuanlan.zhihu.com/p/37331092

C++抽象类 https://zhuanlan.zhihu.com/p/266311842

C++多态 可见“C++面向对象程序设计(下)”一文有关部分https://blog.csdn.net/cnds123/article/details/109602105

猜你喜欢

转载自blog.csdn.net/cnds123/article/details/131832675