C++ 11语法甜点1

来源:互联网 发布:中国最良心的网游知乎 编辑:程序博客网 时间:2024/04/29 13:22

C++ 11中引入了许多简化编程工作的语法上的新特性,我们暂且美其名曰“语法甜点”。下面一一进行介绍。

语法甜点1:序列for循环
序列for循环是一种简化的for循环,可用于遍历一组序列,包括各种容器、string、数组、初始化列表以及由begin和end函数定义的序列。示例代码如下:

vector<int> vctTemp{1, 2, 3};for (auto a : vctTemp){cout << a << endl;}


语法甜点2:委托构造函数

在引入C++ 11之前,如果某个类有多个重载的构造函数,且这些构造函数中有一些共同的初始化逻辑,通常都需要再编写一个带参数的初始化函数,然后在这些构造函数中调用这个初始化函数。在C++ 11中,再也不用这么麻烦了。我们可以实现一个最基础的构造函数,其他构造函数都调用这个构造函数。示例代码如下:
class CPerson{public:CPerson() : CPerson(0, "") { NULL; }CPerson(int nAge) : CPerson(nAge, "") { NULL; }CPerson(int nAge, const string &strName){stringstream ss;ss << strName << "is " << nAge << "years old.";m_strInfo = ss.str();}private:string m_strInfo;};

注意:

1.委托构造函数是在c++0X版本开始支持的

2.C++98支持构造函数调用成员函数,也支持成员函数调用另一个成员函数(非冒号表达式调法,编译能过,但是得不到应该的结果),例子如下:

class CPerson  
{  
public:  
//CPerson() : CPerson(0, "") { NULL; }  
CPerson(int nAge)  

CPerson(nAge, ""); 
}  
CPerson(int nAge, const string &strName)  
{  
stringstream ss;  
ss << strName << "is " << nAge << "years old.";  
m_strInfo = ss.str();  
}  
string m_strInfo;  
void show()
{
std::cout << m_strInfo <<std::endl;
}
};
int main() 

{

CPerson  t(10);
t.show();
return 0;
}

经测试 编译能过,并且CPerson(int nAge, const string &strName) 这个函数也有被调用,但是成员m_strInfo未成功初始化.关于这点原因不是很理解.


语法甜点3:统一的初始化语法

在引入C++ 11之前,有各种不同的初始化语法。在C++ 11中,仍可以使用这些初始化语法,但也可以选择使用新引入的统一的初始化语法。统一的初始化语法用一对大括号{}表示,使用{}初始化语法还可有效地避免窄转换。示例代码如下:
int a{5};char c{'X'};int p[5] = {1, 2,3, 4, 5};vector<int> vctTemp{1, 2, 3};CPerson person{10, "Mike"};int b = 5.3;                     // b赋值成5,发生了窄转换int d{5.3};                      // 会提示编译错误,避免了窄转换


语法甜点4:nullptr

nullptr是C++ 11中新加的一个关键字,用于标识空指针。引入nullptr后,可以解决某些函数重载时的二义性问题。示例代码如下:
void F(int a){cout << a << endl;}void F(char *p){assert(p != NULL);cout << p << endl;}int main(int argc, _TCHAR* argv[]){int *p = nullptr;int *q = NULL;bool bEqual = (p == q);  // 两个指针值是相等的,bEqual为trueint a = nullptr;   // 编译失败,nullptr不是转换为intF(0);          // 在C++ 98中编译失败,有二义性;在C++ 11中调用F(int)F(nullptr);    // 调用F(char *)getchar();return 0;}


语法甜点5:成员变量初始化

与Java和C#中的用法一样,可以对成员变量进行就地初始化。示例代码如下:
class CPerson{private:int m_nAge = 10;string m_strName = "Mike";};


语法甜点6:默认或禁用函数

当我们定义了自己的带参数的构造函数时,编译器将不再生成默认的构造函数,如果此时想使用默认的构造函数,则必须显式地声明并定义不带参数的构造函数。在C++ 11中,我们可以使用default关键字来表明我们希望使用默认的构造函数。类似的,当我们不想外部使用编译器自动生成的构造函数或赋值函数时,我们一般需要将其声明成protected或private的。在C++ 11中,我们可以使用delete关键字来表明我们不希望编译器生成默认的构造函数或赋值函数。示例代码如下:
class CPerson{public:CPerson() = default;CPerson(const CPerson &person) = delete;};


语法甜点7:继承的构造函数

当一个派生类的某个函数隐藏了基类中的某个同名函数时,如果我们想在派生类中导出基类中的这个同名函数,可以通过using Base::Func的方式将基类中的这个同名函数引入到派生类的作用域内。当该方法只对普通成员函数有效,不能用于构造函数。在C++ 11中,如果派生类认为基类的构造函数已经足够,则也可以使用using Base::Base的方式将基类的构造函数引入到派生类的作用域内。但需要注意的是,此时派生类中的成员变量并没有进行初始化,所以应当对这些成员变量进行就地初始化。示例代码如下:
class CBase{};class CDerived : public CBase{public:using CBase::CBase;CDerived(int nData) : m_nData(nData) { NULL; }private:int m_nData = 10;};


语法甜点8:模板右边双括号

在C++ 98中,vector<vector<int>> vctTemp是一个非法的表达式,编译器会认为右边的>>是一个移位操作符,因此必须修改为vector<vector<int> > vctTemp,即在右边的两个>中间添加一个空格。在C++ 11中,这将不再是一个问题,编译器将能够识别出右边的双括号是两个模板参数列表的结尾。

语法甜点9:static_assert
静态断言static_assert由一个常量表达式和一个字符串构成。在编译期间,将计算常量表达式的值,如果为false,字符串将作为错误信息输出。示例代码如下:

char a = 10;static_assert(sizeof(a)==4, "a is not an integer.");


语法甜点10:初始化列表

在引入C++ 11之前,只有数组能使用初始化列表。在C++ 11中,vector、list等各种容器以及string都可以使用初始化列表了。初始化列表对应的类为initializer_list,vector、list等各种容器以及string之所以可以使用初始化列表,是因为它们重载了参数类型为initializer_list的构造函数(称为初始化列表构造函数)和赋值函数(称为初始化列表赋值函数)。下面是一些使用初始化列表的例子。
void Print(const initializer_list<int> &ilData){for (auto a : ilData){cout << a << endl;}}int main(int argc, _TCHAR* argv[]){vector<int> vctNum = {1, 2, 3, 4, 5};map<string, string> mapID2Name = {{"92001", "Jack"}, {"92002", "Mike"}};string strText{"hello world"};Print({});Print({1, 2});Print({1, 2, 3, 4, 5});getchar();return 0;}

0 0
原创粉丝点击