嵌套结构属性继承

Nested struct attributes inheritance

本文关键字:属性继承 结构 嵌套      更新时间:2023-10-16

我读到你可以通过使用继承来扩展结构。我有一个派生类,我希望在其中具有与其父级相同的结构,但扩展了更多字段。这似乎有效,但是当我从修改结构的 Parent 类调用方法时,它在 Child 结构属性中不起作用。在这里,我正在尝试的示例:

class Parent
{
public:
struct info 
{
int a;
};
info data;
virtual void main(void);
};
void Parent::main()
{
data.a =1;
}
class Child: public Parent
{
public:
struct info2: public info
{
int b;
};
info2 data;
virtual void main(void);
};
void Child::main(void)
{
Parent::main();
data.b = 2;
std::cout << data.a << "n";
std::cout << data.b << "n";
}
int main(void)
{
Parent *base;
Child derived;
base = &derived;
base->main();
return 0;
}

这不是打印1 and 2打印0 and 2。所以基本上好像派生类的属性数据没有被调用Parent::main修改。

正确的方法是什么?我完全做错了吗?

你的意思

void Child::main(void)
{
Parent::main();
data.b = 2;
std::cout << Parent::data.a << "n";
std::cout << data.b << "n";
}

派生类中声明的名称data隐藏data基类中声明的名称。因此,您需要使用限定名来访问父类的隐藏成员。

至于派生类的成员数据的数据成员a,则没有初始化。

派生类的对象有两个数据成员data:一个是使用类型信息继承的(其名称隐藏在派生类中(,另一个是派生类自己的数据成员。

基类对派生类的数据成员data一无所知。

您可以在类信息中定义一个虚函数。例如

#include <iostream>
class Parent
{
public:
struct info 
{
int a;
virtual void set( int a )
{
this->a = a;
}
};
info data;
virtual void main(void);
};
void Parent::main()
{
data.set( 1 );
}
class Child: public Parent
{
public:
struct info2: public info
{
int b;
void set( int a ) override
{
this->a = a;
}
};
info2 data;
virtual void main(void);
};
void Child::main(void)
{
data.set( 3 );
data.b = 2;
std::cout << data.a << "n";
std::cout << data.b << "n";
}
int main(void)
{
Parent *base;
Child derived;
base = &derived;
base->main();
return 0;
}

程序输出为

3
2

你是完全正确的,Parent::main()无法访问Child::data,并且对任何神话中的info2类型一无所知; 对它来说,Parent::data就是全部,info是它的类型。

有几种简单的方法可以使Child::main()使用Child::data而不是Parent::data,或者让它从每个版本访问所需的字段,但我怀疑这不是你所追求的。 如果您希望ParentChild看到相同的data(分别作为infoinfo2(,则data本身应该多态使用。 对于此示例,为了简单起见,我将使用常规指针(反过来,在访问data的成员时,operator.将替换为operator->(,但我建议研究智能指针,例如std::unique_ptr以简化内存管理。

class Parent
{
public:
struct info 
{
int a;
// Chances are, it's going to be deleted through an info* no matter what it is.  Therefore, virtual destructor.
virtual ~info() = default;
};
info* data;  // Consider using a smart pointer here, like std::unique_ptr.
virtual void main(void);
virtual void output() const; // Just adding this for convenience.
// Default constructor now allows data to be supplied, or creates it if necessary.
Parent(info* dp = nullptr) : data(dp ? dp : new info) {}
// Correct destructor will always be called.
virtual ~Parent() { if(data) { delete data; } }
};
void Parent::main()
{
data->a =1;
}

我们现在删除字段Child::data,取而代之的是ChildParent的构造函数提供所需的data

class Child: public Parent
{
public:
struct info2: public info
{
int b;
};
//info2 data;
virtual void main(void);
void output() const override; // Just adding this for convenience.
Child() : Parent(new info2) {}
};

Child在需要时,会将data视为info2而不是info

void Child::main(void)
{
Parent::main();
auto dataPtr = static_cast<info2*>(data); // In Child, we know data is an info2*.
dataPtr->b = 2;
// Just gonna move these to output(), for a cleaner illustration.
//std::cout << "Data->a: " << data->a << "n";
//std::cout << "Data->b: " << dataPtr->b << "n";
}

这将导致data按预期工作,ParentChild都具有正确的类型。

void Parent::output() const {
std::cout << "Parent:n";
std::cout << "> Data->a: " << data->a << "n";
}
void Child::output() const /*override*/ {
std::cout << "Child as ";
Parent::output();
auto dataPtr = static_cast<info2*>(data);
std::cout << "Child:n";
std::cout << "> Data->a: " << dataPtr->a << "n";
std::cout << "> Data->b: " << dataPtr->b << "n";
}

然后,这将按预期执行,如在 Koliru 上现场看到的那样。 请注意,如果您希望能够,例如,从预先存在的Parent创建Child,则需要添加一个可以从info进行info2的移动构造函数;您应该考虑遵循五法则,或使用智能指针而不是原始指针。;P

您必须使用以下代码:

void Child::main(void)
{
Parent::main();
data.b = 2;
std::cout << Parent::data.a << "n";
std::cout << data.b << "n";
}