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

6ju8rftf  于 2023-02-20  发布在  其他
关注(0)|答案(1)|浏览(153)

考虑下面的代码(注意:经过合理的批评后,我改写了这个问题):

#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具有DataSuper的示例dataSuper的子类Sub具有相同的对象data,但它是从DataSuper继承的DataSub的示例。
本质上,我想从类Sub访问data.a,我知道我可以用data作为指针,然后使用dynamic_cast,但不确定这是否是一个好的实践。
有没有一种方法可以避免它没有data作为指针?

huwehgph

huwehgph1#

Super::data不是DataSub,但您将其视为DataSub
请记住,在C++中,对象类型为 * 的变量是 * 对象。它不是引用或指针或类似的东西,除非你声明它是。Super::dataDataSuper,它永远不会是其他东西。像这样强制指向DataSub&不会有好结果。
如果你想在SuperSub类之间共享一个DataSub,你需要使用一个指针,例如:

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>());
}

Demo
如果你想避免data的额外分配,你可以反转所有权的方向,也就是说,让Sub传递一个指向DataSub的非拥有指针给Super的构造函数,并让Sub拥有该对象:

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>();
}

Demo
注意,这种方法比第一种方法稍差一些,因为SubSuper子对象初始化时Sub::data还没有初始化,如果你试图在Super的构造函数中使用Super::data指向的对象,你会很快陷入未定义行为的境地,Super的析构函数也是如此。Sub::dataSuper::~Super的主体被执行之前被销毁,因此试图从Super的析构函数主体访问data所指向的对象也将导致未定义的行为。

相关问题