=default
在C++中,当我们设计与编写一个类时,若不显著申明,则类会默认为我们提供如下几个函数:
- 构造函数
- 析构函数
- 拷贝构造函数
- 拷贝赋值函数
- 移动构造函数(C++2.0)
- 移动赋值函数 (C++2.0)
C++11允许添加“=default”说明符到函数声明的末尾,以将该函数声明为显示默认构造函数;这就使得编译器为显示默认函数生成了默认实现,它比手动编程函数更加有效;当我们声明一个有参构造函数时,编译器就不会创建默认构造函数。在这种情况下,我们可以使用default说明符来创建默认构造函数。
#include <iostream>
using namespace std;
class A
{
public:
A(int)
{
cout << "A::A(int)" << endl;
}
//当我们定义了有参构造函数,编译器就不会生成默认的构造函数了,
//通过=default来将该函数声明为默认构造函数
A() = default;
};
int main()
{
A a;//使用默认构造函数
A a1(10);//使用有参构造函数
return 0;
}
=delete
在C ++ 11之前,操作符delete 只有一个目的,即释放已动态分配的内存。而C ++ 11标准引入了此操作符的另一种用法:禁用成员函数的使用,这是通过附加= delete来完成的; 说明符到该函数声明的结尾;使用’= delete’说明符禁用其使用的任何成员函数称为expicitly deleted函数,引进这种新特性的目的是为了增强对“类默认函数的控制”,从而让程序员更加精准地去控制默认版本的函数。
/********************************************************
*
* C++ 2.0之前
*
*********************************************************/
class UnCopyable {
protected:
UnCopyable() {}
~UnCopyable() {}
private:
UnCopyable(const UnCopyable&);
UnCopyable& operator=(const UnCopyable&);
};
class B : private UnCopyable
{
//class 不在声明copy构造函数和拷贝赋值
};
/********************************************************
*
* C++ 2.0
*
*********************************************************/
class C
{
public:
C(){}
~C() {}
C(const C&) = delete;
C& operator=(const C&) = delete;
};
int main()
{
B b1, b2;
//b1 = b2;//error C2280: “B &B::operator =(const B &)”: 尝试引用已删除的函数
//B b3(b1);//error C2280: “B::B(const B &)”: 尝试引用已删除的函数
C c,c1;
//c = c1;//error C2280: “C &C::operator =(const C &)”: 尝试引用已删除的函数
//C c2(c);//error C2280: “C::C(const C &)”: 尝试引用已删除的函数
return 0;
}
using
1. Alias Template的使用
/*
Alias Template:
设计一个模板,并且对这个模板的类型进行typedef操作typedef的话因为不能传递参数T
#define只能实现字符串的替换,并不能达到目的
*/
template<typename T>
using Vec = vector<T, allocator<T>>;
2. 函数指针的定义
//给函数指针做定义,这个也是可以代替typedef的
using func = void(*)();
typedef void(*pFunc)();
3. 在子类中引入基类的成员,并影响访问权限
/*
1、public继承不改变基类成员的访问权限
2、private继承使得基类所有成员在子类中的访问权限变为private
3、protected继承将基类中public成员变为子类的protected成员,其它成员的访问 权限不变。
4、基类中的private成员不受继承方式的影响,子类永远无权访问。
*/
class Base {
public:
Base() { cout << "Base::Base()" << endl; }
int m_value;
int add(int x, int y) {
m_value = x + y;
return m_value;
}
};
/*
//如果在Derived中不添加using Base::add;Derived将无法访问add成员函数
*/
class Derived :private Base {
public:
using Base::add;
int interface(int x, int y)
{
cout << m_value << endl;
}
};
int main()
{
Derived d;
d.add(1,2);//如果在Derived中不添加using Base::add;Derived将无法访问add成员函数
return 0;
}
noexcept
从C++11开始,我们能看到很多代码当中都有关键字noexcept。比如下面就是std::initializer_list的默认构造函数,其中使用了noexcept:
constexpr initializer_list() noexcept
: _M_array(0), _M_len(0) { }
该关键字告诉编译器,函数中不会发生异常,这有利于编译器对程序做更多的优化,如果在运行时,noexecpt函数向外抛出异常(如果函数内部捕捉了异常并完成处理,这种情况不算抛出异常),程序会直接终止,调用std::terminate()函数,该函数内部会调用std::abort()终止程序。
使用noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间,以下情形可以使用noexcept:
- 移动构造函数(move constructor)
- 移动分配函数(move assignment)
- 析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。下面代码可以检测编译器是否给析构函数加上关键字noexcept。
void swap(Type& x, Type& y) throw() //C++11之前
{
x.swap(y);
}
void swap(Type& x, Type& y) noexcept //C++11
{
x.swap(y);
}
/*
有条件的限制noexcept:
如果操作x.swap(y)不发生异常,那么函数swap(Type& x, Type& y)一定不发生异常
*/void swap(Type& x, Type& y) noexcept(noexcept(x.swap(y))) //C++11
{
x.swap(y);
}
以上参考:
- https://blog.csdn.net/liufengl138/article/details/101797756
- https://www.bilibili.com/video/BV11x411Z7zk?p=13