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

时间:2017-04-25 13:57:52

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

我的编译器告诉我:

在复制构造函数'B :: B(const B&amp;)'中: 警告:基类“A类”应该在复制构造函数中显式初始化[-Wextra]          B(const B&amp; object){/ 做某事 /}          ^

什么错了?

3 个答案:

答案 0 :(得分:3)

对于手动复制构造函数(即你的B::B(const B &)),在实践中依赖于被调用的A的默认构造函数是不寻常的(虽然在标准C ++中技术上不是非法的) - 这是如果您实现B的复制构造函数而未在A构造函数的初始化列表中明确初始化B,将会发生什么。

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

B

的复制构造函数
B (const B & object) {/*do somthing*/}

实际上相当于

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

正如我上面所说的那样,在实践中明确地做了很多事情 - 它很少是一种理想的行为。

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

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

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

这里的问题是你的B类继承自A,它本身继承自QObject类,而QObject类并不是可复制的。

因此,如果您已经实现了一个复制构造函数,则无法在类A中复制构造函数。

您仍然可以在B copy ctor B (const B & object) : A()甚至B (const B & object) : A(object)中调用A中的默认构造函数,但它永远不会构建对象的精确副本。

有关Qt选择的详细说明,请参阅http://doc.qt.io/qt-5/object.html#identity-vs-value