__cplusplus 其实被定义为一个整数 , C++03 中被定义为199711L , C++11 中被定义为201103L .
可以通过下面的代码检测编译器是否支持C++11 .
#if __cplusplus < 201103L
#error "Should use C++11 implementation"
#endif
枚举的作用域即是它所在的
namespace
, 有是他的父 作用域 。
例子 :
enum Type { General , Light, Medium , Heavy };
Type t1 = General; // Correct
Type t2 = Type::General ; // Also correct
C++98 的sizeof不能使用非static的类成员作为参数, C++ 11 则可以 .
例子 :
class Test
{
public:
int m_int;
static int s_int;
};
#include <iostream>
using std::cout;
using std::endl;
int main()
{
cout<<sizeof(Test::s_int)<<endl; // both pass
cout<<sizeof(Test::m_int)<<endl; // C++98 error , C++11 pass
return 0;
}
C++11的friend 关键字不必再写class .
支持模板作为friend. 如果模板的实例化是一个基本类型, 那么就忽略这个友元.
例子
template<typename T>
class Test
{
public:
friend T; // C98 需要写出 friend class T , 且 T 需要为具体的类名 .
private:
int a;
};
class FriendClass ;
typedef TestNoFriend Test<int> ;
typedef TestHasFriend Test<FriendClass>;
对于虚函数(非纯虚) , 使用final关键字可以阻止派生类重载继续这个接口.
例子:
#include <iostream>
using std::cout;
using std::endl;
class GrandPa
{
public:
virtual void Print() = 0;
};
class Father : public GrandPa
{
public:
virtual void Print() final { cout<<"Father is always correct ! "<<endl;}
};
class Son : public Father
{
public:
void Print() { /* TODO want son want*/} //error: overriding final function ‘virtual void Father::Print()’
};
使用override关键字修饰函数, 指明这个函数是重载了父类的接口, 如果不是,则会编译出错 .
例子:
class Father
{
public:
virtual void A(){}
};
class Son : public Father
{
public:
virtual void AA() override {} //error: ‘virtual void Son::AA()’ marked override, but does not override
};
- 支持带有默认 值/类型 的函数模板.
- 支持外部(extern) 模板
- 支持局部/匿名类型作为模板实参, 但是这个局部/匿名类型的声明不能出现在模板实参位置.
具体例子请自习查阅书籍.
- 继承构造函数的
用途:
1.1.1 父类的构造函数众多
1.1.2 派生类添加的数据项较少, 可以通过指定默认值(C++11) 的方式初始化
注意:
1.2.1 多重继承的时候注意构造函数冲突问题- 委派构造函数
用途
2.1.1 各种构造函数有部分相同的工作
2.1.2 在初始化列表中使用, 类似父类构造函数的使用
注意:
2.3 注意不应该产生环状依赖
例子 :
#include <iostream>
using std::cout;
using std::endl;
class Father
{
public:
Father() : Father(1) {} // 委派给只有一个参数的构造函数 .
Father(int i) : Father(i,2){} // 委派给最详细赋值的构造函数 .
Father(int i, int j) : a(i) , b(j){}
void Print() {cout<<"a :"<<a<<" b : "<<b<<endl; }
private:
int a;
int b;
};
class Son : public Father
{
public:
using Father::Father; // 继承父类的构造函数
void Print()
{
Father::Print();
cout<<"c :"<<c<<endl;
}
private:
int c = 3 ; // C++11 可以直接对非static成员进行初始化.
};
int main()
{
Son a;
Son b(3);
Son c(3,4);
a.Print();
b.Print();
c.Print();
return 0;
}
// C++98 error , C++11 pass
int a[] = { 1 , 2, 3} ;
int b[] { 4, 5, 6} ;
vector<int> c(1,2,3);
int i = 1024;
int j = 10 ;
char c = {i}; // error , narrowing and miss data
char c = {j}; // pass , narrowing but no data miss.
值的分类
右值引用 T &&
T( T && )
移动语义在需要深层拷贝的类有巨大作用(不必重新开辟内存).
理论上T( const T && )
是可以的 , 但是没有意义, 移动语义决定了我们应该去改变这个右值 .
std::move(a)
返回a
转化为的右值 , 但是a
本身并没有消亡,a
变量被移动函数改变过之后, 或许数据已经混乱, 不应该继续作为普通左值使用.
template< class T>
void IamForwarding< T && t>
{
//IrunCodeActually(static_cast<T && t> );
IrunCodeActually(std::forward(T && t> );
/*
真正使用的时候, 若T是 A & , 则 && 折叠 , 参数是左值.
若T是 A &&, 则 && 折叠 , 参数是右值.
*/
}
定义函数 :
T operator ""_X( P ) {}
其中T为目标类, _X 为字面值后缀 , P 是 " "
部分的类型 , 作为参数传入(整形 , 浮点 , 字符) .
例子 :
struct Walt { unsigned int v; }
Walt operator ""_w(unsigned int v)
{
Walt w ={(unsigned int ) v};
return w;
}
int main()
{
Walt w = 1024_w; // 使用用户自定义字面值
return 0;
}
如果你不像写 AAA:::BBB:::CCC::DDD i = GenXXX();
, 试一试 auto i = GenXXX();
.
int i;
decltype(i) j ; // 提取i的类型来定义j
#### 枚举
强枚举
enum class XXX{… } ;
enum class XXX : XXX[ int , char , long … ] { .. } ;
普通枚举
enum XXX { … } ;
使用 constexpr 修饰的变量或者函数成为编译期间常量, 可以用来声明数组之类 。。 。
constexpr int i = 10 ; // 修饰变量
/* 1. 使用之前必须声明 2. 必须有且仅有一个返回语句 3. 返回值必须是个常量表达式 */
constexpr int GetI() { return 10; } //修饰函数
>>
和> >
>>
是右移 运算符 , C++ 11 会考虑是否是模板的嵌套 .慢慢学习~~