【问题标题】:Polymorphism: accessing derived class elements from a base class array多态性:从基类数组访问派生类元素
【发布时间】:2014-11-28 19:30:32
【问题描述】:

我已经有一段时间没有使用派生类和多态性了,我不知道如何访问派生类数据项。

// Quick example
class Base {
  string data1;  // data1 = "FOO"
};
class ChildA : public Base {
  string data2;
};


int main() {
Base **list;
list = new Base*[1];
base[0] = new ChildA(// data2 = "BAR");
std::cout << base[0]->data1; // FOO
std::cout << base[0]->data2; // Error; no member named "data2" in Base

是否可以从基类数组中检索派生数据?

【问题讨论】:

  • 了解虚拟成员函数(无论如何,您的示例中没有多态性)
  • 类中的访问权限默认为private
  • 关于多态性的重点是设计你的程序,这样你就不会做你的代码正在做的事情。关键是你不想关心类型的细节尤其是而不是他们的内部数据是什么样的。

标签: c++ arrays class dynamic polymorphism


【解决方案1】:

当您通过指向基类的指针查看派生类的实例时,您只能看到基类的成员,因为通常您不知道您正在查看的子类型实例。多态性和虚函数的关键在于,在许多情况下,您可以在不知道它们的实际类型的情况下使用子类型实例。例如,如果要打印有关实例的信息,并且希望在打印ChildA 时包含data2,则可以在Base 中创建一个虚拟toString() 函数并在ChildA 中覆盖它包括data2。然后,您可以在不知道实际类型的情况下调用toString(),如果您的实例实际上是ChildA,您将得到data2

【讨论】:

  • 啊,真令人失望。我真的认为有某种方法可以将其转换为类型并检索数据,但似乎没有。这就是为什么你必须时不时地练习你的旧语言!
  • @user3470131:啊,我不明白你在寻找类型转换。如果您确定类型,则可以执行(static_cast&lt;ChildA*&gt;(base[0]))-&gt;data2,如果不确定,则可以执行(dynamic_cast&lt;ChildA*&gt;(base[0])) - 如果您指定的类型与运行时类型不匹配,后者将生成NULL。但是,如果您需要这样做而不是为了玩耍,您可能需要重新考虑您的设计。
【解决方案2】:

类成员变量默认是私有的。 使用基类指针,根本无法获取派生类成员var。

如果你想这样做,你可能想实现虚拟getter函数,它会帮助你从派生类中获取私有成员函数。

【讨论】:

    【解决方案3】:

    如果基类接口必须知道派生类中可能包含的数据,那么这里是少数几种不会非常危险的方法之一。

    #include <iostream>
    #include <vector>
    #include <utility>
    #include <memory>
    #include <stdexcept>
    
    using namespace std;
    
    class Base {
    public:
        Base(std::string d1 = {"FOO"} ) : _data1 { std::move(d1) } {}
        virtual ~Base() = default; // because polymorphism without a virtual base class is naughty
        const string& data1() const { return _data1; }
    
        virtual bool has_data2() const { return false; }
        virtual const string& data2() const {
            throw invalid_argument {"I don't have data2"};
        };
    
    private:
        string _data1;  // data1 = "FOO"
    };
    
    class ChildA : public Base {
    public:
        ChildA(std::string d2, std::string d1 = {"FOO"})
        : Base { std::move(d1) }
        , _data2 { std::move(d2) }
        {}
    
        bool has_data2() const override { return true; }
        const std::string& data2() const override {
            return _data2;
        };
    
    private:
        string _data2;
    };
    
    int main()
    {
        vector<unique_ptr<Base>> bases;
        bases.push_back(unique_ptr<Base>(new ChildA("bob")));
        bases.push_back(unique_ptr<Base>(new Base("not foo")));
    
        for(const auto& p : bases) {
            cout << p->data1() << ", " << (p->has_data2() ? p->data2() : "no data 2") << endl;
        }
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 2013-02-04
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多