C++11中类的noncopyable(=default和=delete函数)

10 篇文章 0 订阅

在C++11中,如果想要禁止类的拷贝行为只需要把相应的函数设为 = delete即可,参见标准库的std::unique_ptr

unique_ptr (const unique_ptr&) = delete;
unique_ptr& operator= (const unique_ptr&) = delete;

对于普通的类,如果不去查看类的成员函数声明,我们是无法知道该类是否为不可复制的类型。在C++中,利用继承的技巧可以简单实现noncopyable类。

class noncopyable
{
 public:
  noncopyable(const noncopyable&) = delete;
  void operator=(const noncopyable&) = delete;

 protected:
  noncopyable() = default;
  ~noncopyable() = default;
};

而在C++11之前想要如此实现是将对应的函数设置为private属性。那么我们就来详细了解一下这个=delete和=default有什么作用吧。

  • 我们知道C++ 的一个类中默认有下列特殊成员函数,它们分别是:
    • 默认构造函数
    • 析构函数
    • 拷贝构造函数
    • 赋值运算符
    • 取址运算符
    • const取址运算符

前四个特殊函数负责实例化对象、销毁对象以及复制对象。

  • 如果类中没有定义构造函数,则会生成一个默认构造函数。
    #include <iostream>
    class A
    {
    public:
    	void printHello()
    	{
    		std::cout << "hello";
    	}
    private:
    };
    int main()
    {
    	A a;
    	a.printHello();//可以运行,表明a对象成功构造了
    }
    
  • 如果类中有自定义的构造函数,类就不会为其生成默认的构造函数了
    #include <iostream>
    class A
    {
    public:
    	A(int _a)
    	{
    		m_a = _a;
    	}
    	int getA()
    	{
    		return m_a;
    	}
    private:
    	int m_a;
    };
    int main()
    {
    	A a;//编译错误 没有此构造函数 
    	A a(10);//正确
    	std::cout << a.getA();
    }
    
  • 倘若我们想使用默认构造函数,则必须显式地定义
    class A
    {
    public:
    	A(){} //显示定义
    	A(int _a)
    	{
    		m_a = _a;
    	}
    private:
    	int m_a;
    };
    

= default函数

  • C++11 标准引入了一个新特性:"=default"函数。程序员只需在函数声明后加上“=default;”,就可将该函数声明为 "=default"函数,编译器将为其自动生成默认的函数定义体,提高代码的执行效率。
    class A
    {
    public:
    	A() = default;
    	A(int _a){ m_a = _a;]
    	int getA() {return m_a;}
    private:
    	int m_a;
    };
    
  • Tips:
    • default函数仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数。
    class A
    {
    public:
    	A() = default;//正确
    	A(int _a) = default;//错误,构造函数需要没有默认参数
    	int getA() = default;//错误,仅适用于类的特殊成员函数
    }
    
    • default函数既可以在类内声明类外定义,也可以在类内直接定义。

= delete函数

  • =delete函数,编译器会对指定的函数禁用,从而避免了某些非法的函数调用或者类型转换,从而提高了代码的安全性。
  • 编译器能自动生成类之间赋值、拷贝构造函数,在一定程度上减轻了代码量,但对于某些特定情况下,我们是不允许对象之间进行拷贝与赋值的,那么这时候,我们就需要考虑将拷贝、赋值构造函数禁用了:
class A
{
public:
    A();
    A(const A&) = delete;  // 声明拷贝构造函数为 deleted 函数
    A& operator = (const A &) = delete; // 声明拷贝赋值操作符为 deleted 函数
};
  • Tips:
    • 必须在函数第一次声明的时候将其声明为 = delete 函数,否则编译器会报错。
    • = delete 函数特性可以作用于类的特殊成员函数、类的非特殊成员函数、普通成员函数
delete函数的其他作用
  • = delete函数特性还可用于禁用类的某些转换构造函数,从而避免不期望的类型转换
class A
{
public:
    A(double)
    {

    }

    A(int) = delete;
};

  • = delete 函数特性还可以用来禁用某些用户自定义的类的 new 操作符,从而避免在自由存储区创建类的对象
class A
{
public:
    void *operator new(size_t) = delete;
    void *operator new[](size_t) = delete;
};
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值