C++ 为什么访问基类指针向量中的派生类成员会返回错误?

C++ 为什么访问基类指针向量中的派生类成员会返回错误?,c++,C++,简化的问题示例: #include <string> #include <deque> #include <iostream> class Action{ public: std::string name; Action(std::string name){ this->name = name; } }; class Ability : public Action{ public: int b

简化的问题示例:

#include <string>
#include <deque>
#include <iostream>

class Action{
    public:
    std::string name;

    Action(std::string name){
        this->name = name;
    }
};

class Ability : public Action{
public:
    int bar;
    Ability(std::string name) : Action(name){}
};

int main(){
    std::deque<Action*> foo;

    Ability test("asdf");
    test.bar = 122;

    foo.push_back(&test);
    std::cout << foo.at(0)->bar << std::endl;
    return 0;
}
#包括
#包括
#包括
集体诉讼{
公众:
std::字符串名;
操作(标准::字符串名称){
此->名称=名称;
}
};
集体能力:公共行动{
公众:
int-bar;
能力(std::string name):操作(name){}
};
int main(){
性病:德克福;
能力测试(“asdf”);
test.bar=122;
foo.推回(和测试);

std::cout bar首先,我们赞助商的一句话:

现在您已经阅读了上面的链接,您可以看到没有进行切片,因为对象没有复制到
foo
,只复制了一个指向该对象的指针。
功能
在内存
测试
中的任何位置都保持完整

但是…Foo包含指向
动作
,而不是
能力
Foo
的用户无法知道
Foo
的任何给定元素是否是对
动作
的引用、
能力
或他们完全不知道的
动作
的其他子类的引用。非常强大的东西,使用你甚至不知道的东西的能力是存在的,但这是有代价的:你必须像你知道的那样使用它。
Foo
的用户只能使用呈现给他们的界面,即
Action
。有一些方法可以解决这个问题,例如,但在大多数情况下,最好坚持使用提供的界面和允许重载的方法或运算符在后台执行黑魔法,以便对
操作所代表的内容执行正确的操作。如果这意味着您必须

class Action{
    public:
    std::string name;

    Action(std::string name){
        this->name = name;
    }
    virtual int getbar() = 0; // pure virtual method that all subclasses  
                              // of Action must implement
};

class Ability : public Action{
public:
    int bar;
    Ability(std::string name) : Action(name){}
    int getbar()
    {
        return bar;
    }
};
后来

std::cout << foo.at(0)->getbar() << std::endl;

std::cout getbar()首先,我们赞助商的一句话:

现在您已经阅读了上面的链接,您可以看到没有进行切片,因为对象没有复制到
foo
,只复制了一个指向该对象的指针。
功能
在内存
测试
中的任何位置都保持完整

但是…Foo包含指向
动作
,而不是
能力
Foo
的用户无法知道
Foo
的任何给定元素是否是对
动作
的引用、
能力
或他们完全不知道的
动作
的其他子类的引用。非常强大的东西,使用你甚至不知道的东西的能力是存在的,但这是有代价的:你必须像你知道的那样使用它。
Foo
的用户只能使用呈现给他们的界面,即
Action
。有一些方法可以解决这个问题,例如,但在大多数情况下,最好坚持使用提供的界面和允许重载的方法或运算符在后台执行黑魔法,以便对
操作所代表的内容执行正确的操作。如果这意味着您必须

class Action{
    public:
    std::string name;

    Action(std::string name){
        this->name = name;
    }
    virtual int getbar() = 0; // pure virtual method that all subclasses  
                              // of Action must implement
};

class Ability : public Action{
public:
    int bar;
    Ability(std::string name) : Action(name){}
    int getbar()
    {
        return bar;
    }
};
后来

std::cout << foo.at(0)->getbar() << std::endl;

std::cout getbar()这里没有对象切片。这只是静态类型系统的行为。编译器如何知道
foo.at(0)<代码> >动作*>代码>,实际上指向“代码>能力>代码>,而不只是一个普通的代码>动作< /代码>,或者是从代码>动作< /代码>派生的另一个类。C++中没有这样的特性,即通过基类类型的指针访问派生类的数据成员。这里没有问题(并且它不会发生)。。这里没有对象切片。这只是静态类型系统的行为。编译器如何知道
foo.at(0)<代码> >动作*>代码>,实际上指向“代码>能力>代码>,而不只是一个普通的代码>动作< /代码>,或者是从代码>动作< /代码>派生的另一个类。C++中没有这样的特性,即通过基类类型的指针访问派生类的数据成员。这里没有问题(并且它不会发生)。谢谢,我应该更好地组织我的单词,因为我使用指针来防止切片。谢谢,我应该更好地组织我的单词,因为我使用指针来防止切片。