拥有基类指针来访问继承层次结构中所有类的方法

问题描述 投票:0回答:2

我有这个层次结构。 'Bird' 作为基类,'FlyingBird' 是 'Bird' 的子类,'Parrot' 是 'FlyingBird' 的子类。我在 main() 中创建了一个指向 Parrot 对象的 Bird*。 我不明白的是我无法访问任何类的成员函数。只能访问“Bird”类中的方法。 尽管如此,“FlyingBird”和“Parrot”类是“Bird”继承层次结构的一部分。

#pragma once
#include <iostream>
#include <string>

class Bird
{
private:
    std::string type;
public:
    Bird(std::string type)
        : type(type) {

    }

    virtual void eat()
    {
        std::cout << type << " is eating\n";
    }

    virtual void walk()
    {
        std::cout << type << " is walking\n";
    }

    virtual std::string getType() const final {
        return type;
    }

    virtual ~Bird() {}
};

class FlyingBird : public Bird
{
private:
    std::string wingSize;

public:
    FlyingBird(std::string type, std::string wingSize)
        : Bird(type), wingSize(wingSize) {

    }

    virtual void fly()
    {
        std::cout << this->getType() << " is flying\n";
    }

    virtual ~FlyingBird() {}
};

class Parrot : public FlyingBird
{
public:
    Parrot(std::string type, std::string wingSize)
        : FlyingBird(type, wingSize) {

    }

    virtual ~Parrot() {}
};

int main()
{

    // This is unable to call fly()
    Bird* parrot = new Parrot("Blue Parrot", "Large");
    parrot->fly();

    // But this can
    Parrot parrot1("Yellow Parrot", "Extra large");
    parrot1.fly();
}
c++ inheritance
2个回答
0
投票

好吧,让我们澄清一些事情。首先,继承如何在高层次上发挥作用。我将保持解释简单,并且不会过多讨论 C++ 或编译器如何发挥其魔力来实现这一目标。我所说的大部分内容也适用于其他 OOP 语言(考虑 Java、C# 以及一般支持继承的任何语言)。

首先,虽然继承确实是一种双向关系,并且从某些角度来看,您可以这样看待它,但这一切都取决于您如何使用它。在 OOP 中,有一种称为类型之间的“转换”的东西,简称为“将一种类型转换为兼容类型”。兼容类型由继承决定,与成员(指变量字段或函数)无关。 因此,即使 2 个类(理论 Application 类和

Person

)具有

Run()
功能,但如果它们之间没有关系,则无法在它们之间进行转换。
可以通过多种方式完成转换,推荐用于 C++ 的方式是使用 
dynamic_cast
完成。在某些

某些

情况下可以使用

static_cast
,还有不推荐的 C 风格强制转换。 介绍已经足够了,让我们回到您的用例。那么亲子关系如何运作呢?嗯,就像现实生活中一样。一代父母懂事,他们在学校、高中和大学学到了很多东西,他们读过书,有一定的生活经历。然而,从他们出生到孩子成年的大约 60 年里,事情发生了变化。新信息出现,新技术,新概念,以前认为已知的事情现在由于新的证据而显得不正确。
让我们务实地思考一下:想象一下,如果你能回到 75 年前,告诉你的父母或祖父母,不仅电脑将是每个人都通用的,而且它们将是一个不超过 8x8 厘米的东西,你可以佩戴在上面你的手腕,它可以拥有巨大的计算能力。或者您现在可以了解送餐的快递员的实时位置。或者沉浸在虚拟现实中并“看到”来自世界各地的某个人的数字化表现?事物在变化和发展。问题是,在大多数情况下,我们的父母或祖父母无法接受这些新概念。

回到我们的情况,这意味着孩子将从父母那里获得的知识中受益,但父母很可能无法使用孩子所知道的知识。为什么?不同的一代。

因此子类

FlyingBird

可以知道并使用

Bird

类的功能,但

Bird
无法访问
FlyingBird
所拥有的内容。换个角度想想,父类怎么能提前知道子类能做什么呢?
至于代码中的关系,可以这样做:
Bird* parrot = new Parrot("Blue Parrot", "Large");

你可以这样做:

void StudyBird(Bird* bird);

Bird* bird = new Bird("AnyBird");
Bird* parrot1 = new Parrot("Blue Parrot", "Large");
Parrot* parrot2 = new Parrot("Blue Parrot", "Large");

StudyBird(bird);
StudyBird(parrot1);
StudyBird(parrot2);

但是反过来也有局限性:

void StudyParrot(Parrot* bird);

Bird* bird = new Bird("AnyBird");
Bird* parrot1 = new Parrot("Blue Parrot", "Large");
Parrot* parrot2 = new Parrot("Blue Parrot", "Large");

//StudyParrot(bird);  <-- this won't work
StudyParrot(dynamic_cast<Parrot*>(parrot1));
StudyParrot(parrot2);

当然,继承是一个很大的章节,下面还有很多内容。多态性是一方面,虚函数也是一方面。根据您想要深入了解该主题的程度,解释可能会变得相当长。


问题在于表达式

*parrot

0
投票
静态类型

Bird,并且要使

parrot->fly()
工作,它必须包含
fly
方法。但由于
Bird
没有任何这样的方法,所以我们得到错误
error: 'class Bird' has no member named 'fly'
另外,请注意 
FlyingBird::fly()
实际上并没有覆盖

fly

中名为

Base
的任何方法,因为
Base
中没有这样的虚拟方法。
    

© www.soinside.com 2019 - 2024. All rights reserved.