我想知道为什么这个程序不能编译(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;因为编译器抱怨尝试引用已删除的复制构造函数。是否有一些解释这种行为的标准规则?
答案 0 :(得分:6)
删除a函数不会将其从重载决策中删除。该功能仅被定义删除。当重载决策选择该函数时,目的是使程序格式错误。
由于copy c'tor比你提供的特殊基类c'tor更好,所以如果不进行强制转换,重载决策将始终选择它。
如何最好地处理它是有争议的。理论上你可以 让副本c'tor进行类似的包装。然而,我对于没有复制的复制文件感到厌烦。你的millage可能非常。
另一个我个人更熟悉的选择是不提供公共构造函数。相反,让客户通过常规命名函数创建装饰器。像这样:
ActionDecorator decorate(Action& action) {
return {action};
}
现在,类可以真正保持不可复制,客户端永远不需要自己编译。如果他们将ActionDecorator
传递给decorate
,它将在构造实例之前绑定到Action
引用。所以它甚至不会考虑复制c'tor。
然而,该类必须是可移动的,以便在C ++ 17之前工作。