我正在学习C++,我刚刚开始学习虚拟函数。

从我(在书中和网上)读到的内容来看,虚拟函数是基类中的函数,可以在派生类中重写。

但在本书的早些时候,当我学习基本继承时,我能够在派生类中重写基函数,而不使用虚函数。

那么我在这里错过了什么?我知道虚拟函数还有很多,它似乎很重要,所以我想清楚它到底是什么。我只是在网上找不到一个直截了当的答案。


当前回答

下面是一个完整的示例,说明了为什么使用虚拟方法。

#include <iostream>

using namespace std;

class Basic
{
    public:
    virtual void Test1()
    {
        cout << "Test1 from Basic." << endl;
    }
    virtual ~Basic(){};
};
class VariantA : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantA." << endl;
    }
};
class VariantB : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantB." << endl;
    }
};

int main()
{
    Basic *object;
    VariantA *vobjectA = new VariantA();
    VariantB *vobjectB = new VariantB();

    object=(Basic *) vobjectA;
    object->Test1();

    object=(Basic *) vobjectB;
    object->Test1();

    delete vobjectA;
    delete vobjectB;
    return 0;
}

其他回答

下面是一个完整的示例,说明了为什么使用虚拟方法。

#include <iostream>

using namespace std;

class Basic
{
    public:
    virtual void Test1()
    {
        cout << "Test1 from Basic." << endl;
    }
    virtual ~Basic(){};
};
class VariantA : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantA." << endl;
    }
};
class VariantB : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantB." << endl;
    }
};

int main()
{
    Basic *object;
    VariantA *vobjectA = new VariantA();
    VariantB *vobjectB = new VariantB();

    object=(Basic *) vobjectA;
    object->Test1();

    object=(Basic *) vobjectB;
    object->Test1();

    delete vobjectA;
    delete vobjectB;
    return 0;
}

我认为您所指的是这样一个事实:一旦方法被声明为virtual,您就不需要在重写中使用“virtual”关键字。

class Base { virtual void foo(); };

class Derived : Base 
{ 
  void foo(); // this is overriding Base::foo
};

如果在Base的foo声明中不使用“virtual”,那么Derived的foo将只是隐藏它。

以下是我如何理解虚拟函数的含义,以及为什么需要它们:

假设您有以下两个类:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

在主功能中:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

到目前为止还不错,对吧?动物吃普通食物,猫吃老鼠,都没有虚拟食物。

现在让我们稍微改变一下,以便通过一个中间函数调用eat()(本例中的一个普通函数):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

现在我们的主要功能是:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

哦哦。。。我们把一只猫传给func(),但它不会吃老鼠。是否应该重载func()以使其使用Cat*?如果你必须从Animal派生出更多的动物,它们都需要自己的func()。

解决方案是使Animal类中的eat()成为一个虚拟函数:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

主要内容:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

完成。

为什么我们需要虚拟功能?

虚拟函数避免了不必要的类型转换问题,我们中的一些人会争论,当我们可以使用派生类指针来调用派生类中特定的函数时,为什么需要虚拟函数!答案是,它否定了在大型系统开发中继承的全部思想,因为在大型系统中,非常需要使用单指针基类对象。

让我们比较以下两个简单的程序,以了解虚拟函数的重要性:

无虚拟功能的程序:

#include <iostream>
using namespace std;

class father
{
    public: void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

输出:

Fathers age is 50 years
Fathers age is 50 years
son`s age is 26 years

具有虚拟功能的程序:

#include <iostream>
using namespace std;

class father
{
    public:
        virtual void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

输出:

Fathers age is 50 years
son`s age is 26 years
son`s age is 26 years

通过仔细分析这两个输出,可以理解虚拟函数的重要性。

我想添加虚拟函数的另一种用法,尽管它使用了与上述答案相同的概念,但我认为它值得一提。

虚拟析构函数

考虑下面的这个程序,不要将基类析构函数声明为virtual;Cat的内存可能无法清理。

class Animal {
    public:
    ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat() {
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

输出:

删除动物

class Animal {
    public:
    virtual ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat(){
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

输出:

删除动物名称猫删除动物