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. 运算符重载的格式如下: ...
随机推荐
- 【7集iCore3基础视频】7-2 iCore3原理图介绍
iCore3原理图介绍: 高清源视频:http://pan.baidu.com/s/1hsPkifM 密码:ei8ciCore3 购买链接:https://item.taobao.com/item.h ...
- iostat监控磁盘io
1.安装#yum install sysstat 2.启动#/etc/init.d/sysstat start 3.自启动#checkfig sysstat 4.基本使用#iostat -k 2每两秒 ...
- cookbook学习第二弹
1.5怎样实现一个按优先级排序的队列?并且在这个队列上面每次pop操作总是返回优先级最高的那个元素 带有双下划线的方法,会在需要被调用的位置自动被调用 带有单下划线的变量是私有变量 下面利用类heap ...
- C语言 ---- 数组 iOS学习-----细碎知识点总结
#pragma mark - 数组:用来存放同一数据类型的数据 // 数组的定义:类型说明符 数组名[常量表达式] = {值1, 值2, 值3...}; // 定义一个float类型的数组,用来 ...
- 去掉comments
三种comments: /* Test program */ int main() { // variable declaration int a, b, c; /* This is a test m ...
- iOS:集成支付宝支付
一.介绍 支付宝的集成还是比较简单的,按照文档来一步步操作,基本上很顺利.不过,仍然有两个地方会是坑.这里我集成成功了,在此整理一下.说先说一下我遇到的坑如下: 第一个坑:下载的SDK文件AliPay ...
- 导入charts开源库到工程里面
http://blog.csdn.net/zww1984774346/article/details/50608338 http://blog.csdn.net/zww1984774346/artic ...
- 解决SQLSERVER在还原数据时出现的“FILESTREAM功能被禁用”问题
解决SQLSERVER在还原数据时出现的“FILESTREAM功能被禁用”问题 今天由于测试需要,在网上下载了Adventureworks2008实例数据库的BAK文件,进行还原时出现了这样的错误“F ...
- EF CodeFirst 如何通过配置自动创建数据库<当模型改变时>
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 本篇为进阶篇,也是弥补自己之前没搞明白的地方,惭愧 ...
- csuoj 1114: 平方根大搜索
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1114 1114: 平方根大搜索 Time Limit: 5 Sec Memory Limit: ...