在派生类中同时分配多个字段-为什么这样做有效



我希望派生类的构造函数能够从作为该构造函数参数的对象中分配一些数据,而参数类是构造对象本身的父类。

此代码正在工作。但我想知道这是否正确,或者我只是运气好,应该会在不同的运行时条件下崩溃。C++如何在复制过程中计算Args字段的有效地址,因为编译器不知道这是"独立的"Args对象还是更大对象的一部分?既然对象不是多态的,那么dynamic_cast实际上是如何在这里工作的?

#include <iostream>
using namespace std;
struct Base {
    int FieldBInt;
    double FieldBDouble;
    Base () : FieldBInt(10), FieldBDouble(13.5) { }
};
struct Args {
    int FieldAInt;
    string FieldAString;
};
struct Derived : public Base, public Args {
    int FieldDInt;
    double FieldDDouble;
    explicit Derived (const Args & args) : Base(), FieldDInt(40), FieldDDouble(14.5) {
        Args * castedThis = dynamic_cast<Args *>(this);
        *castedThis = args;
    }
};
int main(int argc, char *argv[]) {
    Derived d ({50, "Text"});
    cout << d.FieldBInt << " " << d.FieldBDouble << endl
         << d.FieldAInt << " " << d.FieldAString << endl
         << d.FieldDInt << " " << d.FieldDDouble << endl;
}

代码打印(正确):

10 13.5
50 Text
40 14.5

派生类使用多重继承从Base和Args类继承。使用Args * castedThis = dynamic_cast<Args *>(this);,您可以获得指向d.的Args部分的指针

可以预期,派生对象d以It的Base部分开始,然后是它的Args部分,然后是其自己的成员。我不知道标准是否需要它。

无论如何,dynamic_cast<Base *>(this)dynamic_cast<Args *>(this)会给你不同的地址。

*castedThis = *(&args);将为结构Args生成一个复制赋值运算符。此复制分配运算符将复制Args成员。

当您按照其他用户的建议初始化初始值设定项列表中的Args时,您正在生成并使用复制构造函数,而不是复制赋值运算符。

在您的代码中,d的Arg部分首先默认初始化,然后进行复制赋值。

当然,按照人们的建议,初始化初始化器列表中的基成员会更加清晰。

编辑以回答:既然对象不是多态的,dynamic_cast实际上是如何在这里工作的

在这种情况下,static_cast和dynamic_cast将在这里工作,因为它们都将作为转换强制转换,它们将转化指针。对于static_cast,将在编译时检查是否可以转换,而对于dynamic_cast,则将在运行时检查(在这种情况下没有任何好处)。

从cppreference中读到,我认为C风格的强制转换或显式强制转换也会起作用,因为它似乎应该作为static_cast起作用。

因此,这种情况下的多态性(运行时多态性)与此无关。在编译时或运行时进行类型检查和转换也可以。

注意:您在问题的原始编辑中输入的代码*this = *(&args);给了我以下编译器错误:与"operator="不匹配(操作数类型为"Derived"one_answers"const Args")。该代码调用了一个asignment运算符,该运算符可以从Args对象向Derived对象赋值,而我们还没有定义任何函数来实现这一点。

因为编译器不知道这是否是"独立的"Args对象还是更大物体的一部分?

你直接继承了它。编译器清楚地知道。事实上,在这种情况下,标准将dynamic_cast定义为等于static_cast,这相当于Args* castedThis = this;

最新更新