在 C++ 中,如何从曾经创建为子类但后来复制到超类的对象的子类中访问属性?

In C++, how to access attributes from a subclass of an object that was once created as subclass, but then copied to superclass?

提问人:Chicoscience 提问时间:2/18/2023 最后编辑:Chicoscience 更新时间:2/18/2023 访问量:81

问:

考虑下面的代码(注意:在受到正确的批评之后,我改写了这个问题):

#include <vector>
using std::vector;

class DataSuper {
    public:
        DataSuper() {}
};

class DataSub : public DataSuper {
    public:
        int a;
        DataSub() {}
};

class Super {
    public:
        DataSuper data;
        Super() {}
};    

class Sub : public Super {
    public:
        Sub(DataSub i) {
            data = i;
        }
        
        void test() {
           // I would like to print the value of data.a
        }
};    

int main(int argc, char *argv[]) {
    DataSub dataSub;
    Super* s = new Sub(dataSub);
    s->test();
    delete(s);
    return 0;
}

Super有一个称为 的实例。,的子类 具有相同的对象,但它是 的实例,继承自 。DataSuperdataSubSuperdataDataSubDataSuper

从本质上讲,我想从课堂访问.我知道我可以通过 having 作为指针然后使用 来做到这一点,但不确定这是否是好的做法。data.aSubdatadynamic_cast

有没有办法避免它而不作为指针?data

C++ 继承 强制转换

评论

3赞 Nathan Pierson 2/18/2023
您的使用是错误的。 不是实例。这是一个实例。告诉编译器将其视为占用更多空间的 ,这是自找麻烦。你需要重新考虑你的设计。static_castSuper::dataDataSubDataSuperDataSub
1赞 Sam Varshavchik 2/18/2023
此外,缺少虚拟析构函数会导致未定义的行为。
0赞 Retired Ninja 2/18/2023
除了潜在的内存泄漏之外,此代码还存在其他问题。godbolt.org/z/cqqv3WK7v
1赞 Yksisarvinen 2/18/2023
请从一本好书中学习 C++,而不是猜测它应该如何工作。如果你从坚实的基础开始,你会为自己省去很多痛苦。
1赞 Remy Lebeau 2/18/2023
相关新闻: 什么是对象切片? 的构造函数在将其参数分配给成员时对其进行切片SubiSuper::data

答:

2赞 Miles Budnek 2/18/2023 #1

Super::data不是 ,但你把它当作一个。DataSub

请记住,在 C++ 中,对象类型的变量对象。它不是引用或指针或类似的东西,除非您声明它是。 是一个,它永远不可能是其他任何东西。像你在这里那样强行指向它不会有好结果。Super::dataDataSuperDataSub&

如果要在 your 和 classes 之间共享 a,则需要使用指针。例如:DataSubSuperSub

class Super
{
public:
    std::unique_ptr<DataSuper> data;
    Super(std::unique_ptr<DataSuper> data) : data{std::move(data)} {}
};

class Sub : public Super
{
public:
    using Super::Super;

private:
    // Use this if you need to treat data as a DataSub
    DataSub& dataSub()
    {
        return static_cast<DataSub&>(*data);
    }
};

int main()
{
    std::unique_ptr<Super> s = std::make_unique<Sub>(std::make_unique<DataSub>());
}

演示


如果你想避免这所需的额外分配,你可以反转所有权方向。也就是说,将非拥有指针传递给 to 的构造函数并拥有该对象:dataSubDataSubSuperSub

class Super
{
public:
    Super(DataSuper* data) : data{data} {}
    
private:
    DataSuper* data;
};

class Sub : public Super
{
public:
    Sub() : Super{&data} {}

private:
    DataSub data;
};

int main()
{
    std::unique_ptr<Super> s = std::make_unique<Sub>();
}

演示

请注意,这种方法比第一种方法的安全性略低,因为在初始化子对象时尚未初始化。如果你尝试使用 's 构造函数中指向的对象,你很快就会陷入未定义行为的境地。的析构函数也是如此。 在执行 的主体之前被销毁,因此尝试访问 from 的析构函数主体所指向的对象也会导致未定义的行为。Sub::dataSubSuperSuper::dataSuperSuperSub::dataSuper::~SuperdataSuper

评论

0赞 Chicoscience 2/18/2023
非常感谢,这很有帮助。我更改了我的代码以使用您的第一个建议,unique_ptr和make_unique,它就像一个魅力。