为什么删除拷贝构造函数不允许使用具有多态类型的其他构造函数?

时间:2018-03-08 12:56:57

标签: c++ polymorphism copy-constructor deleted-functions

我想知道为什么这个程序不能编译(msvc,gcc和clang上的相同行为):

#include <iostream>

using namespace std;

struct Action
{
    virtual void action()
    {
        cout << "Action::action()\n";
    }
};

struct ActionDecorator : Action
{
    ActionDecorator(const ActionDecorator&) = delete;
    ActionDecorator(Action & action) : origAction(action)
    {
    }

    void action() override
    {
        decoration();
        origAction.action();
    }

private:
    void decoration()
    {
        cout << "ActionDecorator::decoration()\n";
    }

    Action & origAction;
};

int main()
{
    Action action;
    ActionDecorator actionDecorator(action);
    ActionDecorator actionDecorator2(actionDecorator);
    actionDecorator2.action();
}

根据我的期望,删除的拷贝构造函数应该让其他ActionDecorator实例构造ActionDecorator,因为它是Action的多态类型。相反,我必须将ActionDecorator实例显式转换为Action&amp;因为编译器抱怨尝试引用已删除的复制构造函数。是否有一些解释这种行为的标准规则?

1 个答案:

答案 0 :(得分:6)

删除a函数不会将其从重载决策中删除。该功能仅被定义删除。当重载决策选择该函数时,目的是使程序格式错误。

由于copy c'tor比你提供的特殊基类c'tor更好,所以如果不进行强制转换,重载决策将始终选择它。

如何最好地处理它是有争议的。理论上你可以 让副本c'tor进行类似的包装。然而,我对于没有复制的复制文件感到厌烦。你的millage可能非常。

另一个我个人更熟悉的选择是不提供公共构造函数。相反,让客户通过常规命名函数创建装饰器。像这样:

ActionDecorator decorate(Action& action) {
  return {action};
}

现在,类可以真正保持不可复制,客户端永远不需要自己编译。如果他们将ActionDecorator传递给decorate,它将在构造实例之前绑定到Action引用。所以它甚至不会考虑复制c'tor。

然而,该类必须是可移动的,以便在C ++ 17之前工作。