多态:从基类数组访问派生类元素

时间:2014-11-28 19:30:32

标签: c++ arrays class dynamic polymorphism

我暂时没有使用派生类和多态,我无法弄清楚如何访问派生类数据项。

// 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

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

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:0)

默认情况下,类成员变量是私有的。 通过使用基类指针,您无法获得派生类成员var。

如果您愿意,可能需要实现虚拟getter函数,它将帮助您从派生类中获取私有成员函数。

答案 2 :(得分:0)

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

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