【问题标题】:Why does the subclass call its parent's method instead of it's own?为什么子类调用其父类的方法而不是它自己的方法?
【发布时间】:2014-01-22 11:16:30
【问题描述】:

我正在自学 C++,但遇到了我没想到的行为。我不确定,但确实认为这不是 Java 在类似情况下会做的事情。为什么DogCat 依赖父类实现并发出通用声音?

#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;
}

结果:

Woof
Generic animal sound
Meow
Generic animal sound

【问题讨论】:

  • 因为“ani”是Animal类型(它不是指向基类的指针,而是基类本身)。
  • 你说得对,Java 不会这样做,主要是因为Animal ani = anim; 在 Java 和 C++ 中表示两个 非常 不同的东西(引用语义与值语义)。

标签: c++ class inheritance methods virtual


【解决方案1】:
Animal ani = anim;

这将创建一个Animal 类型的新对象,而不管anim 的类型如何。所以ani.speak() 将调用Animal::speak,因为这是Animal 类型的覆盖。

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

Animal & ani = anim;

然后动态类型将被保留,T::speak 将被调用。这类似于在 Java 中复制对象引用时发生的情况;但是您不应该尝试从 Java 的角度来理解 C++ 对象模型,因为它们非常不同。

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

virtual void speak() = 0; // Really not implemented

抽象类不能作为一个完整的对象实例化,所以如果你尝试这样做会导致编译时错误。

【讨论】:

  • 有什么方法可以优雅地检查 anim 是 Animal 子类的一个实例吗?如果您尝试执行 please_talk();,我希望编译器大喊
【解决方案2】:

Animal ani = anim; 这一行从特定动物创建了一个通用动物。它被称为切片,因为您丢失了原始派生类。

你需要把它改成引用或者指针:

Animal& ani = anim;

Animal* pAni = &anim;

【讨论】:

    【解决方案3】:

    这都是因为您拥有 Animal 类的实际对象,而不是指向 Animal 类的指针或引用。因此,如果您希望调用 dog 和 Cat 的 speak() 方法,请参考父类 Animal 的指针或指针。否则你会得到动物的 speak() 方法,因为方法是根据实际对象调用的,而不是多态中的引用。

    【讨论】:

      猜你喜欢
      • 2016-01-13
      • 2019-11-15
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      相关资源
      最近更新 更多