如何在C++中通过继承删除构造函数与运算符?
实现不可拷贝/不可移动类的优雅方案
需求背景
需要实现两个辅助类no_copy和no_move,让子类继承后自动具备对应特性:
- 继承
no_copy的类,等价于手动删除拷贝构造函数和拷贝赋值运算符 - 继承
no_move的类,等价于手动删除移动构造函数和移动赋值运算符
示例效果如下:
class base : no_copy { /* 等价于: base(const base&)=delete; base& operator=(const base&)=delete; */ }; class base2 : no_move { /* 等价于: base2(base2&&)=delete; base2& operator=(base2&&)=delete; */ };
当前宏实现的问题
目前通过宏实现该功能,虽然能正常工作,但存在明显缺陷:
// 无限定名的类 #define __NO_COPY__(__class__) __class__::__class__(const __class__&)=delete; __class__& __class__::operator=(const __class__&)=delete; // 有限定名的类 #define __NO_COPY_LIB__(__qualified_name__,__class__) __qualified_name__::__class__(const __class__&)=delete; __class__& __qualified_name__::operator=(const __class__&)=delete;
补充使用示例:
namespace wrapper { class my_class {}; __NO_COPY__(my_class); } __NO_COPY_LIB__(::wrapper::my_class,my_class);
宏的问题在于:
- 语法不美观,破坏代码结构
- 可出现在类定义或实现的任意位置,后续代码重构难度大
期望能在类定义内部直接声明,比如通过模板继承的形式:
class base : public attributes<no_copy,no_move> {}; // 对应的模板包装器 template <typename... _BCs/*Base Classes*/> struct attributes : public _BCs... {};
核心需求是便捷定义类的拷贝/移动特性,同时支持易重构的实现方式,疑问是「通过继承基类来删除子类的构造函数/运算符是否可行」。
可行解决方案
方案1:继承式基类实现(推荐)
利用C++的规则:如果基类的拷贝/移动构造/赋值运算符被delete,子类若未显式定义对应成员,编译器会隐式删除子类的对应成员(因为生成默认版本时需要调用基类的delete成员,导致编译错误)。
实现no_copy和no_move基类:
// 不可拷贝基类 class no_copy { protected: // 允许子类构造和析构,禁止外部直接实例化 no_copy() = default; ~no_copy() = default; // 删除拷贝相关成员 no_copy(const no_copy&) = delete; no_copy& operator=(const no_copy&) = delete; }; // 不可移动基类 class no_move { protected: no_move() = default; ~no_move() = default; // 删除移动相关成员 no_move(no_move&&) = delete; no_move& operator=(no_move&&) = delete; };
子类使用时直接继承,或通过模板包装器整合:
// 模板包装器,支持同时继承多个特性类 template <typename... Bases> struct attributes : public Bases... {}; // 用法示例:同时不可拷贝+不可移动 class base : public attributes<no_copy, no_move> {}; // 单独不可拷贝 class copy_prohibited : public no_copy {};
这种方式完全符合需求,代码结构清晰,所有特性声明都集中在类的继承列表中,便于重构。
方案2:类内宏声明(非继承方式)
如果不想用继承,可以将宏限定在类内部使用,固定声明位置,提升可维护性:
#define NO_COPY(class_name) \ class_name(const class_name&) = delete; \ class_name& operator=(const class_name&) = delete; #define NO_MOVE(class_name) \ class_name(class_name&&) = delete; \ class_name& operator=(class_name&&) = delete;
使用示例:
class base { public: base() = default; ~base() = default; NO_COPY(base) NO_MOVE(base) };
方案3:C++20标准库方案
C++20开始,标准库在<utility>头文件中提供了std::noncopyable,直接继承即可实现不可拷贝:
#include <utility> class base : public std::noncopyable {};
对于不可移动特性,可自行实现no_move基类,与std::noncopyable组合使用。
内容的提问来源于stack exchange,提问作者Amrit Sanjeev
相关产品推荐
相关产品推荐

