如何使用派生类的属性和基类构造函数初始化派生类?

How can I initialize a derived class using its attributes and the base class constructor?

提问人:CaG 提问时间:6/23/2023 最后编辑:CaG 更新时间:6/24/2023 访问量:91

问:

从基类开始,我想创建一些派生类,这些派生类在许多数据成员的值上彼此不同。这些不同的属性在 BaseClass 构造函数中用于初始化其他数据成员。下面你可以找到一个简化的例子来说明我的意思;

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d) {};
    std::string d = "Hello";
};

class DerivedClass2 : public BaseClass {
public:
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d) {};
    std::string d = "Goodbye";
};

但是,我肯定做错了什么,因为我得到了.实现这一点的正确方法是什么?warning: field 'd' is uninitialized when used here [-Wuninitialized]

C++ 继承派 生类

评论

2赞 463035818_is_not_an_ai 6/23/2023
当你通过调用这个构造函数来构造一个时,你想成为什么?你期望做什么?dDerivedClass1DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d), d(d);d(d)
3赞 463035818_is_not_an_ai 6/23/2023
“我肯定做错了什么”是的,这就是为什么仅凭代码不足以解释你想做什么。请尝试解释在构造对象时应该发生什么。预期结果是什么?
0赞 Carsten 6/23/2023
如果是一个常数,就像你的例子一样,为什么不简单地调用?如果它不是常量,则必须在调用基类构造函数之前对其进行初始化。请注意,调用派生的构造函数没有意义,可能是导致此警告的原因 - 您正在尝试使用 的值进行初始化,此时该值尚未初始化,也没有任何意义,因为我猜预期的结果无论如何都是这样。dBaseClass(a, b, c, "Goodbye")d(d)ddd = d
0赞 CaG 6/23/2023
@463035818_is_not_an_ai 我希望每个派生类都由 的构造函数进行初始化,考虑到成员是不同的。@Carsten,是恒定的。但是,我介绍的只是一个 MWE。在我的实际代码中,我更改了不同的数据成员,其中大多数都不是简单的标准数据类型。我同意这是无用的,但删除它不会改变警告的问题(编辑以反映这一点)。BaseClassddd(d)
0赞 Ted Lyngmo 6/23/2023
为什么不搬进去呢?dBaseClass

答:

-1赞 Shreeyash Shrestha 6/23/2023 #1

在你给定的代码中,我认为你在这里错过了一点。在代码中:

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

您已在构造函数中为基类设置了 4 个值。即 这意味着每当您调用基类的构造函数时,您都应该传入 4 个参数,而在此代码中: int a, double b, int c, std::string d


class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Hello";
};

class DerivedClass2 : public BaseClass {
public:
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Goodbye";
};

在这两堂课上,你一直在传递一些我不知道是什么的东西。 换言之,只需删除 .d(d)d(d)

编辑:我发现你在这里也错过了一些东西:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Hello";
};

将代码块 : 置于构造函数的作用域之外。进行以下更改: std::string d="Hello";

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

class DerivedClass1 : public BaseClass {
public:
 std::string d="Anything you want to initialize d to is here";
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d) {
   //Constructor code
}
};

class DerivedClass2 : public BaseClass {
public:
 std::string d="Same here as well";
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d) {
    //Constructor code
}
};

你就可以开始了。希望能有所帮助!!

评论

0赞 CaG 6/23/2023
我编辑了要删除的问题,因为这是一个错误(请参阅我在问题下的评论)。但是,此答案预见到派生类有 4 个输入。我只想有 3 个输入,因为字符串是常量和硬编码的。d(d)d
0赞 Shreeyash Shrestha 6/24/2023
我对代码进行了一些更改。看一看
0赞 Miles Budnek 6/23/2023 #2

您的问题是基本子对象是第一个初始化的东西。也就是说,这个:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : BaseClass(a, b, c, d)
    {};
    std::string d = "Hello";
};

本质上等同于:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : BaseClass(a, b, c, d),
        d("Hello")
    {};
    std::string d;
};

d在被 的构造函数初始化之前传递给 的构造函数。BaseClassDerivedClass1

要解决此问题,您可以引入另一个包含额外成员的基类:

class DerivedBase {
public:
    DerivedBase(std::string d) : d(d) {}
    std::string d;
};

class DerivedClass1 : public DerivedBase, public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : DerivedBase("Hello"),
        BaseClass(a, b, c, d)
    {}
};

由于基类是按照它们在类声明的 base-clause 中列出的顺序初始化的,因此将在 之前初始化,因此在传递给 的构造函数之前已经初始化。DerivedBaseBaseClassdBaseClass

0赞 user1806566 6/24/2023 #3

问题在于,在派生类构造期间,基类构造函数在初始化派生类成员之前运行。这就是为什么编译器抱怨在调用基类构造函数时未初始化的原因 作为参数。dd

如果我们保持你的声明不变,我认为你需要重复自己才能得到你想要的。

class DerivedClass1 : public BaseClass {
public:
  DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, "Hello") {};
  std::string d = "Hello";
};

当然,重复自己并不是一件好事,但避免它意味着重构你的代码。 显然是一个概念(或者它的构造函数中不需要它)。如果将数据成员移动到 ,则初始化顺序问题将毫无意义。dBaseClassBaseClass

评论

0赞 user1806566 6/24/2023
这与@Miles Budnek的回答相同。我们一定在同一时间写下了我们的答案......