7.2 C++11默认函数的控制

一、默认函数

C++默认会实现一些函数,其中类成员函数有:

  • 构造函数
  • 析构函数
  • 拷贝构造
  • 赋值函数(=)
  • 移动构造
  • 移动赋值

以及一些全局操作函数:

  • operator,
  • operator&
  • operator&&
  • operator*
  • operator->
  • operator->*
  • operator new
  • operator delete

二、=default

显示缺省,对于默认生成的函数而言,并不是默认所有都会生成,而是在需要时才会生成。而且当用户自己实现其中的某个函数时,编译器就会移除相应的默认函数,这样就会导致类变得不是POD了。

C++11提供了=default关键字,用于默认函数定义之后,表示要求编译器生成对应的默认函数,从而确保类的POD。

class Empty
{
public:
	Empty() = default;
	Empty(int i) {}
};

int main()
{
	std::cout << std::is_pod<Empty>::value << std::endl;	//1
}

除了在类内指定default外,也可以在类外指定,但是类外指定依旧不是pod类型,类外指定的好处是:可以通过

class Empty
{
public:
	Empty() = default;
	Empty(int i) {}
	Empty& operator=(Empty&);
};
inline Empty& Empty::operator=(Empty&)=default;

int main()
{
	std::cout << std::is_pod<Empty>::value << std::endl;	//0
}

三、=delete

  1. 与default对应的还有显示删除delete表示,显示删除某个函数。最常见的例子就是单例中需要屏蔽拷贝、析构等函数,以前的做法是通过私有化不定义,但是还是可以被友元访问。

从C++11开始,可以直接在函数参数列表后添加=delete删除此函数,被删除的函数无法重载:

fun() = delete;
  1. 显示删除除了屏蔽函数之外,还可以用于抑制隐式类型转换:
class ConvType {
public:
ConvType(int i) {};
ConvType(char c) = delete;  // 删除char版本
};
void Func(ConvType ct) {}
int main() {
    Func(3);
    Func('a');  // 无法通过编译
    ConvType ci(3);
    ConvType cc('a');    // 无法通过编译
}
  1. 而说到抑制隐式转换,还有一种方式是explicit关键字,当一个函数使用explicit和delete同时修饰时,反而会出现一些问题:
        class ConvType {
        public:
            ConvType(int i) {};
            explicit ConvType(char c) = delete;  // 删除explicit的char构造函数
        };
        void Func(ConvType ct) {}
        int main() {
            Func(3);
            Func('a');       // 可以通过编译
            ConvType ci(3);
            ConvType cc('a');    // 无法通过编译
        }

这里对于explicit ConvType(char c)函数而言,意味着拒绝从字符char隐式转换为ConvType类型,因此 Func('a');按explicit的本意是无法通过编译的,但是此处添加了=delete之后,反而移除了explicit的本意。

对比前面的ConvType(char c) = delete;而言,对于Func('a');则优先调用ConvType(char c)进行隐式类型转换,但是由于此函数已经被删除,所以无法构造函数。

因此通常不建议将explicit于delete关键字用于同一个函数上。

  1. delete除了应用于类成员函数外,还可以应用于普通函数:
        void Func(int i){};
        void Func(char c) = delete;  // 显式删除char版本
        int main(){
            Func(3);
            Func('c');  // 本句无法通过编译
            return 1;
        }
        // 编译选项:g++ -std=c++11 7-2-8.cpp
  1. 除此之外,还可以用于删除new函数,使得类只能创建于栈,而不能创建于堆上。
        #include <cstddef>
        class NoHeapAlloc{
        public:
            void * operator new(std::size_t) = delete;
        };
        int main(){
            NoHeapAlloc nha;
            NoHeapAlloc * pnha = new NoHeapAlloc;    // 编译失败
            return 1;
        }
        // 编译选项:g++ -std=c++11 7-2-9.cpp
  1. 以及删除析构函数,使得类只能创建于堆,而不能创建于栈上。(此时该对象是不需要被释放的(无法被释放))
        #include <cstddef>
          #include <new>
          extern void* p;
          class NoStackAlloc{
          public:
              ~NoStackAlloc() = delete;
          };
          int main(){
              NoStackAlloc nsa;    // 无法通过编译
              new (p) NoStackAlloc(); // placement new, 假设p无需调用析构函数
              return 1;
          }
          // 编译选项:g++ 7-2-10.cpp -std=c++11-c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值