为什么子类调用其父方法而不是它自己的方法?

pep*_*dip 0 c++ methods virtual inheritance class

我自己学习c ++并且遇到了一个我没想到的行为.我不确定,但确实认为这不是Java在类似情况下会做的事情.为什么是DogCat依靠TE父类的实现,使一个普通的声音?

#include <iostream>

class Animal{
    public:
        virtual void speak(){std::cout << "???" << std::endl; /* not implemented */}
};

class Dog : public Animal{
    public:
        virtual void speak(){
            std::cout << "Woof" << std::endl;
        }
};

class Cat : public Animal{
    public:
        virtual void speak(){
            std::cout << "Meow" << std::endl;
        }
};

class Desk{
    /* Not an animal */
};

template<class T>
void please_talk(){
    T anim;
    Animal ani = anim;
    anim.speak();
    ani.speak();
}

int main()
{
    please_talk<Dog>();
    please_talk<Cat>();
    /* Does not compile please_talk<Desk>(); */
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果:

Woof
Generic animal sound
Meow
Generic animal sound
Run Code Online (Sandbox Code Playgroud)

Mik*_*our 5

Animal ani = anim;
Run Code Online (Sandbox Code Playgroud)

Animal无论类型如何,都会创建一个新的类型对象anim.所以ani.speak()会调用Animal::speak,因为这是类型的覆盖Animal.

如果你要创建一个引用(或指针)

Animal & ani = anim;
Run Code Online (Sandbox Code Playgroud)

那么动态类型将被保留,T::speak并将被调用.这类似于复制对象引用时Java中发生的情况; 但是你不应该试图用Java来理解C++对象模型,因为它们非常不同.

您可以通过使基类抽象来防止意外创建基类对象(有时称为"切片",因为它会切除对象的派生类部分).也就是说,使用默认实现声明函数pure virtual,而不是非pure:

virtual void speak() = 0; // Really not implemented
Run Code Online (Sandbox Code Playgroud)

抽象类无法实例化为完整对象,因此如果您尝试这将导致编译时错误.