C++ 这种奇怪的多态行为需要解释
我在学习多态性并尝试了一些基本的东西。在下面的代码中,我在基类C++ 这种奇怪的多态行为需要解释,c++,polymorphism,C++,Polymorphism,我在学习多态性并尝试了一些基本的东西。在下面的代码中,我在基类Animal中有一个虚拟函数display()。我创建了两个派生类,Dog,继承自Animal,和Tommy继承自Dog。display()函数仅在一个派生类中被重写(Tommy类在下面的代码中) 在main()函数中,我通过基类指针指向派生对象 ptr = &dog; ptr->display(); 但是,它最终调用了Dog(即Animal)的父类的display()。出于好奇,我删除了其他派生类中的display(
Animal
中有一个虚拟函数display()
。我创建了两个派生类,Dog
,继承自Animal
,和Tommy
继承自Dog
。display()
函数仅在一个派生类中被重写(Tommy
类在下面的代码中)
在main()
函数中,我通过基类指针指向派生对象
ptr = &dog;
ptr->display();
但是,它最终调用了Dog
(即Animal
)的父类的display()
。出于好奇,我删除了其他派生类中的display()
函数并检查了输出,但我得到了相同的行为,总是调用display()父类的
。我不知道为什么会发生这种情况。我想我遗漏了一些东西。请帮助
#include <iostream>
using namespace std;
class Animal
{
protected:
string name;
public:
Animal(string nam):name(nam){}
virtual void display()const {cout<<"Base class.\n";}
};
class Dog : public Animal
{
public:
Dog(string nam):Animal(nam){}
};
class Tommy : public Dog
{
public:
Tommy(string nam):Dog(nam){}
void display()const{cout<<"i am "<<name<<endl;}
};
int main()
{
Animal *ptr;
Dog dog("trace");
Tommy tom("tommy");
ptr = &dog;
ptr->display();
ptr = &tom;
ptr->display();
return 0;
}
但是,它最终调用了Dog(即Animal)父类的display()
这完全是预期的行为,因为您没有覆盖派生类Dog
中的虚拟函数display
为了使派生类具有特定的行为,必须实现非纯虚拟函数display
。您已经在Tommy
类中实现了该函数,但在Dog
类中没有这样的实现
但是,它最终调用了Dog(即Animal)父类的display()
这完全是预期的行为,因为您没有覆盖派生类Dog
中的虚拟函数display
为了使派生类具有特定的行为,必须实现非纯虚拟函数
display
。您已经在Tommy
类中实现了该函数,但在Dog
类中没有这样的实现。第一次显示值时,它是Dog类型的。狗对显示没有重新定义,它使用动物的显示,因为它继承了这个功能
第二次显示值时,其类型为Tommy。Tommy重新定义了显示功能,即“我是Tommy”。它将显示此字符串,因为它重新定义了此虚拟函数
这是因为汤米是一种动物,因为汤米继承了狗,而狗继承了动物。这样想:每个汤米都是动物,但不是每个动物都是汤米或狗
虚是C++中的一个关键词,意思是函数可以在儿童类中重新定义。
编辑:只是澄清一下什么是纯虚拟函数和虚拟函数。纯虚函数表示需要在其子类中重新定义函数,否则它将无法编译(即,该函数的基类中没有实现)。虚拟函数声明可以在其子类中重新定义它(它在基类中有一个实现)。在本例中,显示是一个虚拟函数,而不是纯函数。第一次显示值时,它是Dog类型。狗对显示没有重新定义,它使用动物的显示,因为它继承了这个功能 第二次显示值时,其类型为Tommy。Tommy重新定义了显示功能,即“我是Tommy”。它将显示此字符串,因为它重新定义了此虚拟函数 这是因为汤米是一种动物,因为汤米继承了狗,而狗继承了动物。这样想:每个汤米都是动物,但不是每个动物都是汤米或狗
虚是C++中的一个关键词,意思是函数可以在儿童类中重新定义。
编辑:只是澄清一下什么是纯虚拟函数和虚拟函数。纯虚函数表示需要在其子类中重新定义函数,否则它将无法编译(即,该函数的基类中没有实现)。虚拟函数声明可以在其子类中重新定义它(它在基类中有一个实现)。在本例中,display是一个虚拟函数,而不是纯函数。那么,即使虚拟函数不是纯函数,我也必须重写它,这是一种强迫吗?不,当然不是。您的示例表明您不必重写它。您必须在派生类中实现纯虚函数。对于非纯虚函数,不存在派生类可以使用基类的默认实现的强制操作。@artm:您不需要在派生类中实现纯虚函数。派生类本身可以保持抽象。但在类层次结构的同一点上,您将希望得到一个具体的类,然后必须实现纯虚函数。@ChristianHackl是的,我的意思是继承层次结构中的最后一个叶类必须实现纯虚函数-正如你所说,层次结构中的中间派生类仍然可以是抽象的。那么,我必须重写虚函数,即使它不是纯函数,这是一种强迫吗?不,当然不是。您的示例表明您不必重写它。您必须在派生类中实现纯虚函数。对于非纯虚函数,不存在派生类可以使用基类的默认实现的强制操作。@artm:您不需要在派生类中实现纯虚函数。派生类本身可以保持抽象。但在类层次结构的同一点上,您将希望得到一个具体的类,然后必须实现纯虚函数。@ChristianHackl是的,我的意思是继承层次结构中的最后一个叶类必须实现纯虚函数-正如您所说,层次结构中的中间派生类仍然可以是抽象的。这就是它的方式
Base class.
i am tommy