基类“A 类”应在复制构造函数中显式初始化

Vla*_*nin 7 c++ qt

我对编译器警告感到困惑。我使用了 MinGW 5.3.0 32bit 并尝试编译此代码:

#include <QCoreApplication>
#include <QObject>
#include <QDebug>    

class A : public QObject
    {
        Q_OBJECT

    public:
        A(QObject* parent = 0){ Q_UNUSED(parent);}
        ~A() {qDebug()<<"~A()";}

        virtual void func(){}
    private:

    };

    class B : public A
    {
        Q_OBJECT

        public:
            B(){}
            B (const B & object) {/*do somthing*/}
            ~B(){}

            void func(){/*do somthing*/}
    private:

    };

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);

        return a.exec();
    }
Run Code Online (Sandbox Code Playgroud)

我的编译器告诉我:

在复制构造'B :: B(常数B&)':警告:基类的类A'应在复制构造明确初始化[-Wextra] B(const的B&对象){/做财产以后/} ^

怎么了?

Pet*_*ter 6

对于手动复制构造函数(即您的B::B(const B &)),在实践中依赖A被调用的默认构造函数是不寻常的(尽管在标准 C++ 中技术上不是非法的)- 如果您在B没有显式初始化的情况下实现复制构造函数,则会发生这种情况在A中的初始化器列表B构造函数。

您的编译器配置为警告此类事情。这是编译器的实施质量问题(在这种情况下,他们不需要发出警告)。但是,实际上,您的编译器供应商正在帮您一个忙。

你的复制构造函数 B

B (const B & object) {/*do somthing*/}
Run Code Online (Sandbox Code Playgroud)

实际上相当于

B (const B & object) : A() {/*do somthing*/}
Run Code Online (Sandbox Code Playgroud)

正如我上面所说,在实践中明确地这样做是不寻常的 - 这很少是一种理想的行为。

关闭编译器以使其不发出此警告的方法是ABs 构造函数的初始化列表中显式构造。你可以像上面那样使用默认构造函数A(理论上,它可能会或可能不会阻止编译器抱怨),但更常用的技术类似于

B (const B & object) : A(object) {/*do somthing*/}
Run Code Online (Sandbox Code Playgroud)

请记住, 的复制构造函数A将在B构造函数体之前调用(即首先构造基类)。

更好的是,如果可能,您最好根本不定义复制构造函数。在这种情况下(假设某些东西不会阻止它这样做,例如private基类的复制构造函数),编译器将自动生成一个复制构造函数,用于B使用它们的复制构造函数(递归地)初始化其所有基类及其所有数据成员。


Tom*_*mek 0

您正在为 B 类编写复制构造函数,但您的父类 A 是默认构造的。我(大概还有编译器)希望 B 的复制构造函数也复制构造其父级。鉴于 A 中有析构函数和虚函数,您应该认真考虑为 A 创建复制构造函数或完全禁用它。