Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 多态性:从基类数组访问派生类元素_C++_Arrays_Class_Dynamic_Polymorphism - Fatal编程技术网

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

C++ 多态性:从基类数组访问派生类元素,c++,arrays,class,dynamic,polymorphism,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

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

// 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
//快速示例
阶级基础{
字符串data1;//data1=“FOO”
};
ChildA类:公共基础{
字符串数据2;
};
int main(){
基本**列表;
列表=新基*[1];
base[0]=新的ChildA(//data2=“BAR”);
std::cout data1;//FOO
std::cout data2;//错误;Base中没有名为“data2”的成员

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

当您通过指向基类的指针查看派生类的实例时,您只能看到基类的成员,因为通常情况下,您不知道正在查看的是哪个子类型实例。多态性和虚函数的要点是在许多情况下,您可以在不知道其实际类型的情况下处理子类型实例。例如,如果您希望打印有关实例的信息,并且希望在打印
ChildA
时包含
data2
,您可以创建一个虚拟的
toString()
函数在
Base
中调用,并在
ChildA
中重写它以包含
data2
。然后,您可以调用
toString()
,而不知道实际的类型,如果您的实例实际上是
ChildA
,您将得到
data2
类成员变量,默认情况下是私有的。 通过使用基类指针,您根本无法获取派生类成员变量


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

如果基类接口必须了解派生类中可能包含的数据,那么以下是几种不太危险的方法之一

#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;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
阶级基础{
公众:
Base(std::stringd1={“FOO”}):\u data1{std::move(d1)}{
virtual~Base()=default;//因为没有虚拟基类的多态性是顽皮的
常量字符串&data1()常量{return\u data1;}
虚拟布尔具有_data2()常量{return false;}
虚拟常量字符串&data2()常量{
抛出无效的_参数{“我没有数据2”};
};
私人:
字符串_data1;//data1=“FOO”
};
ChildA类:公共基础{
公众:
ChildA(std::string d2,std::string d1={“FOO”})
:Base{std::move(d1)}
,_data2{std::move(d2)}
{}
bool具有_data2()常量重写{return true;}
常量std::string&data2()常量重写{
返回数据2;
};
私人:
字符串_data2;
};
int main()
{
向量基;
基地。推回(独特的ptr(新儿童(“bob”));
基地。推回(独特的基地(新基地(“非福”));
用于(常数自动和p:基准){

cout data1()data2():“no data 2”)阅读有关虚拟成员函数的内容(无论如何,您的示例中没有多态性)默认情况下,类中的访问权限为
private
。多态性的关键是设计程序,使您不必执行代码正在执行的操作。关键是您不想关心类型的细节,特别是不关心其内部数据的外观。您可能会读到:啊,这令人失望。我真的很失望ght有一些方法可以将它转换为类型并检索数据,但似乎没有。这就是为什么你必须时不时地练习你的旧语言!@user3470131:啊,我不明白你在寻找类型转换。如果你确定类型,你可以做
(静态转换(base[0])->data2
,或者
(动态转换)(base[0])
如果您没有-如果指定的类型与运行时类型不匹配,则后者将生成
NULL
。但是如果您需要执行此操作而不是玩游戏,则可能需要重新考虑您的设计。