C++11中对类(class)新增的特性
C++11中对类(class)新增的特性
default/delete 控制默认函数
在我们没有显式定义类的复制构造函数和赋值操作符的情况下,编译器会为我们生成默认的这两个函数:
默认的赋值函数以内存复制的形式完成对象的复制。
这种机制可以为我们节省很多编写复制构造函数和赋值操作符的时间,但是在某些情况下,比如我们不希望对象被复制,
在之前我们需要将复制构造函数和赋值操作符声明为private,现在可以使用delete关键字实现:
class X {
// …
X& operator=(const X&) = delete; // 禁用类的赋值操作符
X(const X&) = delete;
};
显式地使用default关键字声明使用类的默认行为,对于编译器来说明显是多余的,但是对于代码的阅读者来说,使用default显式地定义复制操作,则意味着这个复制操作就是一个普通的默认的复制操作。
override /final 强制重写/禁止重写虚函数
派生类中可以不实现基类虚函数,也可以实现,但不使用virtual关键字;
这很容易给人造成混淆,有时为了确认某个函数是否是虚函数,我们不得不追溯到基类查看;
C++11引入了两个新的标识符: override和final
override,表示函数应当重写基类中的虚函数。(用于派生类的虚函数中)
final,表示派生类不应当重写这个虚函数。(用于基类中)
struct B {
virtual void f();
virtual void g() const;
virtual void h(char);
void k(); // non-virtual
virtual void m() final;
};
struct D : B {
void f() override; // OK: 重写 B::f()
void g() override; // error: 不同的函数声明,不能重写
virtual void h(char); // 重写 B::h( char ); 可能会有警告
void k() override; // error: B::k() 不是虚函数
virtual void m(); // error: m()在基类中声明禁止重写
};
有了这对兄弟,我们的虚函数用起来更为安全,也更好阅读;
委托构造函数 Delegating constructors
在C++98中,如果你想让两个构造函数完成相似的事情,可以写两个大段代码相同的构造函数,或者是另外定义一个init()函数,让两个构造函数都调用这个init()函数。例如:
class X {
int a;
// 实现一个初始化函数
validate(int x) {
if (0<x && x<=max) a=x; else throw bad_X(x);
}
public:
// 三个构造函数都调用validate(),完成初始化工作
X(int x) { validate(x); }
X() { validate(42); }
X(string s) {
int x = lexical_cast<int>(s); validate(x);
}
// …
};
这样的实现方式重复罗嗦,并且容易出错。
在C++0x中,我们可以在定义一个构造函数时调用另外一个构造函数:
class X {
int a;
public:
X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
// 构造函数X()调用构造函数X(int x)
X() :X{42} { }
// 构造函数X(string s)调用构造函数X(int x)
X(string s) :X{lexical_cast<int>(s)} { }
// …
};
继承的构造函数 Inheriting constructors
C++11提供了将构造函数晋级的能力:
比如以下这个示例,基类提供一个带参数的构造函数,而派生类没有提供;
如果直接使用D1 d(6);将会报错;通过将基类构造函数晋级,派生类中会隐式声明构造函数D1(int);
需要注意的是,晋级后的基类构造函数是无法初始化派生类的成员变量的,所以如果派生类中有成员变量,
需要使用初始化列表初始化;
struct B1 {
B1(int) { }
};
struct D1 : B1 {
using B1::B1; // 隐式声明构造函数D1(int)
// 注意:在声明的时候x变量已经被初始化
int x{0};
};
void test()
{
D1 d(6); // d.x的值是0
}
类内部成员的初始化 Non-static data member initializers
在C++98标准里,只有static const声明的整型成员能在类内部初始化,并且初始化值必须是常量表达式。这些限制确保了初始化操作可以在编译时期进行。
class X {
static const int m1 = 7; // 正确
const int m2 = 7; // 错误:无static
static int m3 = 7; // 错误:无const
static const string m5 = “odd”; //错误:非整型
};
C++11的基本思想是,允许非静态(non-static)数据成员在其声明处(在其所属类内部)进行初始化。这样,在运行时,需要初始值时构造函数可以使用这个初始值。现在,我们可以这么写:
class A {
public:
int a = 7;
};
它等同于使用初始化列表:
class A {
public:
int a;
A() : a(7) {}
};
单纯从代码来看,这样只是省去了一些文字输入,但在有多个构造函数的类中,其好处就很明显了:
class A {
public:
A(): a(7), b(5), hash_algorithm(“MD5″),
s(“Constructor run”) {}
A(int a_val) :
a(a_val), b(5), hash_algorithm(“MD5″),
s(“Constructor run”)
{}
A(D d) : a(7), b(g(d)),
hash_algorithm(“MD5″), s(“Constructor run”)
{}
int a, b;
private:
// 哈希加密函数可应用于类A的所有实例
HashingFunction hash_algorithm;
std::string s; // 用以指明对象正处于生命周期内何种状态的字符串
};
可以简化为:
class A {
public:
A() {}
A(int a_val) : a(a_val) {}
A(D d) : b(g(d)) {}
int a = 7;
int b = 5;
private:
//哈希加密函数可应用于类A的所有实例
HashingFunction hash_algorithm{“MD5″};
//用以指明对象正处于生命周期内何种状态的字符串
std::string s{“Constructor run”};
多么优雅!
移动构造和移动赋值
在C++98中,我们自定义的类,会默认生成拷贝赋值操作符函数和拷贝赋值函数以及析构函数;
在C++11中,依赖于新增的move语义,默认生成的函数多了2个移动相关的:移动赋值操作符( move assignment )和移动构造函数( move constructor );
BS建议,如果你显式声明了上述 5 个函数或操作符中的任何一个,你必须考虑其余的 4 个,并且显式地定义你需要的操作,或者使用这个操作的默认行为。
一旦我们显式地指明( 声明 , 定义 , =default , 或者 =delete )了上述五个函数之中的任意一个,编译器将不会默认自动生成move操作。
一旦我们显式地指明( 声明 , 定义 , =default , 或者 =delete )了上述五个函数之中的任意一个,编译器将默认自动生成所有的拷贝操作。但是,我们应该尽量避免这种情况的发生,不要依赖于编译器的默认动作。
如果你声明了上述 5 个默认函数中的任何一个,强烈建议你显式地声明所有这 5 个默认函数。例如:
template<class T>
class Handle {
T* p;
public:
Handle(T* pp) : p{pp} {}
// 用户定义构造函数: 没有隐式的拷贝和移动操作
~Handle() { delete p; }
Handle(Handle&& h) :p{h.p}
{ h.p=nullptr; }; // transfer ownership
Handle& operator=(Handle&& h)
{ delete p; p=h.p; h.p=nullptr; } // 传递所有权
Handle(const Handle&) = delete; // 禁用拷贝构造函数
Handle& operator=(const Handle&) = delete;
// ...
};
参考
http://www.stroustrup.com/C++11FAQ.html
https://www.chenlq.net/books/cpp11-faq
Posted by: 大CC | 02SEP,2015
博客:blog.me115.com [订阅]
Github:大CC
C++11中对类(class)新增的特性的更多相关文章
- 关于c++11中static类对象构造函数线程安全的验证
在c++11中,static静态类对象在执行构造函数进行初始化的过程是线程安全的,有了这个特征,我们可以自己动手轻松的实现单例类,关于如何实现线程安全的单例类,请查看c++:自己动手实现线程安全的c+ ...
- callable object与新增的function相关 C++11中万能的可调用类型声明std::function<...>
在c++11中,一个callable object(可调用对象)可以是函数指针.lambda表达式.重载()的某类对象.bind包裹的某对象等等,有时需要统一管理一些这几类对象,新增的function ...
- 22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表。然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法showB输出大写的英文字母表。最后编写主类C,在主类的main方法 中测试类A与类B。
22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表.然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法sh ...
- 一起学习c++11——c++11中的新增的容器
c++11新增的容器1:array array最早是在boost中出现:http://www.boost.org/doc/libs/1_61_0/doc/html/array.html 当时的初衷是希 ...
- C++中的类继承(2)派生类的默认成员函数
在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...
- C++11 中function和bind以及lambda 表达式的用法
关于std::function 的用法: 其实就可以理解成函数指针 1. 保存自由函数 void printA(int a) { cout<<a<<endl; } std:: ...
- C++ 11中几个我比较喜欢的语法(三)
随着Vsisual Studio 2013 RC版的放出,之前承诺的对C++ 11语法支持已经全部完成,本文是C++ 11中我喜欢的语法系列的最后一部分(一),(二). 非静态成员直接初始化 在C++ ...
- 对C++11中的`移动语义`与`右值引用`的介绍与讨论
本文主要介绍了C++11中的移动语义与右值引用, 并且对其中的一些坑做了深入的讨论. 在正式介绍这部分内容之前, 我们先介绍一下rule of three/five原则, 与copy-and-swap ...
- C++ primer plus读书笔记——第11章 使用类
第11章 使用类 1. 运算符重载是一种形式的C++多态. 2. 不要返回指向局部变量或临时对象的引用.函数执行完毕后,局部变量和临时对象将消失,引用将指向不存在的数据. 3. 运算符重载的格式如下: ...
随机推荐
- PHP读文件的一个乱码问题
D:/3.txt是utf-8文件 $f1 = fopen('D:/3.txt','r');$str = fread($f1,10000);fclose($f1);echo substr($str,1, ...
- .gitignore文件不起作用
当我们用git时常常会习惯把我们不想上传到远程代码库中的一些本地文件(夹)放在一个叫做.gitignore的文件中,例如常见的本地build文件夹,一些IDE如Intellig,Eclipse的项目管 ...
- MySQL- -Join语法解析与性能分析
Mysql Join语法解析与性能分析 一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ...
- 土壤湿度传感器YL69使用
1.电源:3.3V ~ 5V 2.获取湿度信息的方式(2种可同时使用): 从传感器的D0引脚:土壤湿度大于某个阈值,则D0输出0,否则输出1 从传感器的A0引脚:获取到模拟量,更加精确.土壤湿度越大, ...
- ASP.NET Page执行顺序【转】
一.ASP.NET 母版页和内容页中的事件 母版页和内容页都可以包含控件的事件处理程序.对于控件而言,事件是在本地处理的,即内容页中的控件在内容页中引发事件,母版页中的控件在母版页中引发事件.控件事件 ...
- openfire及xmpp简单介绍
一.oprenfire 1.openfire是采用Java开发,开源的实时协作(RTC)服务器基于XMPP(Jabber)协议.可以使用它轻易的构建高效率的即时通信服务器. 2.Openfire安装和 ...
- oracle 判断字符串是否日期格式
select case when to_char(TO_DATE(NVL('2015- 8', 'a'), 'yyyy-mm'),'yyyy-mm')='2015- 8' then 1 else 0 ...
- CSS之cssText
更改元素样式 <div style="width:100px;height:100px;text-align:center;line-height:100px;"> T ...
- Netty5.x中新增和值得注意的点
最近事情多,OneCoder折腾了好几天,总算翻译完成了. 翻译自官方文档:http://netty.io/wiki/new-and-noteworthy-in-5.x.html 该文档会列出在N ...
- WWDC 2013 Session笔记 - iOS7中的多任务
这是我的WWDC2013系列笔记中的一篇,完整的笔记列表请参看这篇总览.本文仅作为个人记录使用,也欢迎在许可协议范围内转载或使用,但是还烦请保留原文链接,谢谢您的理解合作.如果您觉得本站对您能有帮助, ...