默认的可复制派生类

时间:2018-01-04 11:14:41

标签: c++

假设我有一个愚蠢的类层次结构。

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;
};

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }
private:
    std::vector<int> stuff;
};

我想这样使用它:

void printIt(Base* b) {
    b->print();
}

int main() {

    Derived d1;
    Derived d2 = d1;

    printIt(&d1);
    printIt(&d2);
}

这编译并且工作正常,但Clang警告我:

  

警告:不推荐使用'Base'的隐式复制构造函数的定义,因为它具有用户声明的析构函数

这似乎很正确 - 如果人们复制Base会发生不好的事情,所以我会删除复制构造函数。

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;

    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;
};

但是我得到了这个错误:

main.cpp:38:17: error: call to implicitly-deleted copy constructor of 'Derived'
        Derived d2 = d1;
                ^    ~~
main.cpp:18:21: note: copy constructor of 'Derived' is implicitly deleted because base class 'Base' has a deleted copy
      constructor
    class Derived : public Base {
                    ^
main.cpp:14:9: note: 'Base' has been explicitly marked deleted here
        Base(const Base&) = delete;
        ^

好的......够公平的。如果我尝试明确地添加它会怎么样?

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }

    Derived(const Derived&) = default;

private:
    std::vector<int> stuff;
};

然后:

main.cpp:40:17: error: call to implicitly-deleted copy constructor of 'Derived'
        Derived d2 = d1;
                ^    ~~
main.cpp:27:9: note: explicitly defaulted function was implicitly deleted here
        Derived(const Derived&) = default;
        ^
main.cpp:18:21: note: copy constructor of 'Derived' is implicitly deleted because base class 'Base' has a deleted copy
      constructor
    class Derived : public Base {
                    ^
main.cpp:14:9: note: 'Base' has been explicitly marked deleted here
        Base(const Base&) = delete;
        ^

没有快乐,这也是有道理的。这里有什么解决方案?我应该忽略原来的警告吗?也许我应该将Base(Base&)等添加为protected

2 个答案:

答案 0 :(得分:1)

因此,如果我复制/分配protected,它会在没有警告的情况下编译。这似乎是一个合理的解决方案:

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;

protected:        
    Base(const Base&) = default;
    Base& operator=(const Base&) = default;
};

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }

private:
    std::vector<int> stuff;
};

void printIt(Base* b) {
    b->print();
}

int main() {

    Derived d1;
    Derived d2 = d1;

    printIt(&d1);
    printIt(&d2);
}

答案 1 :(得分:0)

如果你想像Derived d2 = d1;那样使用它,你需要做三件事:

1)使Base复制(和移动)构造函数和赋值运算符protected而不是deleted委托允许/禁止复制/移动到派生类的功能

protected: Base(const Base&) = default;
protected: Base& operator=(const Base&) = default;

2)使Derived复制(和移动)构造函数和赋值运算符public以指示允许复制/移动

public: Derived(const Derived&) = default;
public: Derived& operator=(Derived&) = default;

3)将Derived标记为final,以防止有人决定再次从中获取意外切片

class Derived final: public Base