C++新特性学习(2)

续接C++新特性学习(1)

2.通用性方面


继承构造函数


C++98: 不支持

           派生类可以自动获得基类的成员和接口(虚函数和纯虚函数),但非虚函数就无法派生使用,这包括构造函数。在构造派生类时,需要在初始化列表中显式调用基类的构造函数,以此完成派生类的构造。


                存在一种特例:基类A实现了多种构造函数以及其它成员,派生类B继承自A,B中仅提供了成员函数但没有成员变量。因此构造B就等于构造A,按照C++98的标准就需要在B中”透传”很多A的构造函数。(自己不写编译器也会生成)


 

C++11:

                C++98中using关键字的特性如下:当派生类使用基类的成员函数时,可以使用using关键字声明。



                C++11把using关键字的特性扩展到了构造函数上,子类可以使用using声明来声明继承基类的构造函数,这样子类就再不需要”透传”构造函数了。


                继承构造函数只能初始化基类的成员变量,无法初始化派生类成员变量。派生类可以使用声明时初始化或者自定义构造函数完成成员初始化。

注意:子类继承了基类的构造函数,那么子类就不会自动生成默认构造函数。


委派构造函数


C++98:不支持

                在C++98标准中,如果一个类中有多个构造函数,为了减少代码的冗余,我们可能会这样设计一个类的构造函数。

class InfoC98 {
public:
       InfoC98(): type(123),name("name") {initReset(); }
       InfoC98(int i) :type(i),name("name") {initReset(); }
       InfoC98(char e):type(123),name(e)  {initReset(); }
 
private:
       void initReset() {/*其他初始化 */ }
   int  type;
   char name;
   //...
};

C++11:新标准中提供了委派构造函数。委派构造函数允许类中的一个构造函数通过初始化列表方式来调用同一个类中的另一个构造函数。是减少冗余代码和重复代码的好办法,能提高代码的可读性。上述代码可以如下修改:

class Info {
public:
   Info() : Info(1, 'a') { }//委派构造函数
   Info(int i) : Info(i,'a') { } //委派构造函数
   Info(char e): Info(1, e) { } //委派构造函数
 
private:
   Info(int i,char e):type(i), name(e) {/* 其他初始化 */ }//目标构造函数
   int  type;
   char name;
   //...
};

     代码中委派构造函数委托目标构造函数完成构造类。使用时需要注意:(1)构造函数不可同时“委派”和初始化构造列表。(2)注意成员变量的构造顺序:编译时,先构造目标构造函数再构造委派构造函数。这是因为,初始化列表的构造先于构造函数函数体。(3)构造函数即可以是委派构造函数也可以是目标构造函数,因此可以形成委托链。但不要形成委托环,会编译报错。


右值引用

C++98:

广泛认同的说法,可以取地址的、有名字的为左值;反之不能取地址的、没有名字的为右值。对于a =b + c;这条语句,&a是可以通过编译的,而&(b+c)会编译报错,因此a是一个左值,(b +c)为右值

C++11:

右值由两个概念构成:将亡值(xvalue,eXpiring Value)和纯右值(prvalue,Pure Rvalue)。纯右值就是C++98中的右值概念,用于辨别临时变量和不与对象关联的值,比如返回值为非引用值的临时变量值。将亡值是C++新增的跟右值引用相关的表达式。这种表达式通常将被移动的对象移为它用。C++11所有的值必为左值、将亡值和纯右值三者之一。

       右值引用是对一个右值进行引用的类型。由于右值通常不具有名字,因此只能通过引用的方式找到右值。比如 T&& a = ReturnRvalue();假设ReturnRvalue()返回一个右值,我们就声明了一个名为a的右值引用,其值等于ReturnRvalue()函数返回的临时变量的值。

       相对于C++98中的引用”&”,在C++11称为左值引用。无论左值引用还是右值引用都属于引用类型,必须立即初始化。其原因为引用类型本身不拥有所绑定对象的内存,只是该对象的一个别名。左值引用是有名变量的别名,右值引用则是匿名变量的别名。

       在上面的表达式中,ReturnRvalue()函数的返回值应该是其作用域内的一个局部变量的副本,即一个临时变量。该临时变量作为右值返回。在返回的右值在语句结束后,其生命也就终结了。但由于有右值引用的声明,该右值又“重获新生”,其生命期将和右值引用类型变量a的生命期一样,只要a还在,该右值临时变量会一直存在。

       相对于非右值引用语句:T b= ReturnRvalue();该表达式返回的右值临时变量需要一次赋值和析构,赋值就会带来对象的构造。右值引用a直接绑定了ReturnRvalue()的临时变量,而b是由临时值构造而成的。右值引用减少了右值临时变量的构造和析构的开销。

注意:右值引用是不可以绑定左值的,比如inta; int &&b = a;这样不会编译通过。

       C++98中的左值引用”&”和”const&”能否绑定右值。看以下语句:

T & e = ReturnRvalue();//编译error
Const T & e = ReturnRvalue();//编译ok

       非const左值引用无法绑定右值,const左值引用可以绑定右值。这是因为在C++98中开始const左值引用就是个“bug级”引用类型,它可以接受非常量左值、常量左值、右值对其进行初始化。而且它也可以像右值引用一样将将亡值的生命期延长,只不过将亡值在延长的生命期中是“只读”的。以下代码可以看出非const左值引用和const左值引用的使用区别:

#include <iostream>
using namespace std;
 
struct C
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值