2-1.打印标准库等信息【2-1-1.cpp】
2-2.利用宏定义__func__打印文件名【2-1-2.cpp】
2-3.C++11运行__func__用于类和结构体中
2-4-1.一个简单的变长参数宏的应用
2-4-2.用__cpluscplus宏来强制使用户使用支持C++11及以上的编译器来编译【2-4-1.cpp】
2-5.C++11中用宏定义查看long long类型相关的值
2-6.assert宏用于运行时断言-演示报错【2-5-1.cpp】
2-7.assert宏用于运行时断言示例-演示一个编译器对象支持的编译风格的“静态断言”【2-5-2.cpp】
2-8. assert宏用于运行时断言示例-演示两种数据类型的长度保证一致的“静态断言”【2-5-3.cpp】
2-9-1.用“除0”这种静态断言实现在模版实例化的时候的编译器的报错【2-5-4-1.cpp】
2-9-2.用static_assert实现编译时产生清晰的报错【2-5-4-2.cpp】
2-10.static_assert可以用于任何命名(名字)空间--简单示例【2-5-5.cpp】
2-11.static_assert的断言表达式必须时可以计算的表达式(常量表达式),变量会出错【2-5-6.cpp】
2-12. 被noexcpt修饰的函数一旦抛异常,编译器就会直接调用std::terminate()来终止程序的运行【2-6-1.cpp】
2-13.C++11中类的构造和析构函数默认不抛异常,除非显示指定或类的基类或成员有noexcept(false)的析构函数
2-14.C++98的静态成员常量的“就地”声明中的限制
2-15.C++11中使用就地圆括号的表达式列表初始化非静态成员会导致编译出错【2-7-2.cpp】
2-16 .C++11中用各种手段初始化非静态成员【2-7-3.cpp】
2-17. 多个构造函数且有多个成员变量的时候可以看出C++11新方式带来的便利
2-18.书中在C++98标准中的sizeof不能对非静态成员使用,但为啥我用的C++98标准的时候的编译器是能通过的呢?【2-8-1.cpp】
2-19.书中说C++98在什么友元类的时候需要加class关键字,为啥我的98不加也可以呢?
2-20.利用2-19中的变化为类模板声明友元【2-9-2.cpp】
2-21.利用危险方法且不优雅的方法写出测试程序【2-9-3.cpp】
2-22.针对2-21的缺陷,利用类模板与友元结合实现良好的封装代码-【2-9-4.cpp】
2-23.基类的成员函数fun被声明为virtual的时候,对于其派生类来说,fun总是可以被重写覆盖的【2-10-1.cpp】
2-24.final关键字使得派生类不可以通过重写来覆盖它所修饰的虚函数
2-25-1.虚函数描述符override可以帮我们的编译器做一些辅助检查
2-25-2.一个正确使用override的示例
2-26.一个简单的例子回顾一下函数模板【2-11-1-1.cpp】
2-27.C++98标准不支持函数模板的默认模板参数,C++11中开始支持函数模板的默认模板参数【2-11-1-2.cpp】
2-28.C++11中类模板的默认参数必须遵循从右至左的规则,函数模板的默认参数指定没有规则【2-11-2.cpp】
2-29.模板函数的默认形参不是模板参数推导的依据,函数模板参数的选择,总是由函数的实参推导出来的
2-30.C++11针对C++98中的局部和匿名类型不能作为模板类的实参做出调整【2-13-1.cpp】
nclude
using namespace std;
int main()
{
cout << "Standard Clib:"<<__STDC_HOSTED__<
#include
#include
using namespace std;
const char* hello(){
return __func__;
}
const char* world(){
return __func__;
}
int main(){
cout << hello()<<","<
#include
using namespace std;
struct TestStruct{
TestStruct(): name(__func__){}
const char *name;
};
int main(){
TestStruct ts;
cout<< ts.name <
#include
#define LOG(...){\
fprintf(stderr,"%s:Line %d:\t",__FILE__,__LINE__);\
fprintf(stderr,__VA_ARGS__);\
fprintf(stderr,"\n");\
}
int main(){
int x = 3;
// ....
LOG("x=%d",x);
return 0;
}
#include
#include
#if __cplusplus < 201103L
#error "should use C++11 implementation"
#endif
int main()
{
printf("test\n");
}
本例子还可以用作编译时断言的测试代码.
#include
#include
#ifdef __cplusplus
#define DD 900
#endif
using namespace std;
int main(){
long long ll_min = LLONG_MIN;
long long ll_max = LLONG_MAX;
unsigned long long ull_max = ULLONG_MAX;
printf("min of long long: %lld\n",ll_min);
printf("max of long long: %lld\n",ll_max);
printf("max of unsigned long long: %llu,ULLONG_MAX:%llu\n",ull_max,ULLONG_MAX);
printf("DD is %d\n",DD);
return 0;
}
#include
using namespace std;
char * ArrayAlloc(int n){
assert(n>0);//assert that n must be greater than 0
return new char [n];
}
int main(){
char* a = ArrayAlloc(0);
return 0;
}
#include
#include
using namespace std;
enum FeatureSupports{
C99 = 0x0001,
ExInt = 0x0002,
SAssert = 0x0004,
NoExcept = 0x0008,
SMAX = 0x0010,
};
struct Compiler{
const char * name;
int spp;
};
int main(){
// check if the all enums are here
assert((SMAX-1)==(C99 | ExInt | SAssert | NoExcept));
Compiler a = {"abc",(C99 | SAssert)};
//...
if(a.spp & C99){
printf("a.spp = %d , C99 = %d ,test line = %d, compiler %s supports C99.\n",a.spp,C99,__LINE__,a.name);
}else{
printf("a.spp = %d , C99 = %d ,test line = %d, compiler %s does not support C99.\n",a.spp,C99,__LINE__,a.name);
}
if(a.spp & SMAX){
printf("a.spp = %d , SMAX = %d , test line = %d,compiler %s supports SMAX \n",a.spp,SMAX,__LINE__,a.name);
}else{
printf("a.spp = %d , SMAX = %d , test line = %d,compiler %s does not support SMAX. \n",a.spp,SMAX,__LINE__,a.name);
}
return 0;
}
#include
#include
using namespace std;
template
int bit_copy(T&a ,U&b){
assert(sizeof(b)== sizeof(a));
memcpy(&a,&b,sizeof(b));
};
int main(){
int a = 0x2468;
double b;
bit_copy(a,b);
return 0;
}
#include
using namespace std;
#define assert_static(e)\
do{\
enum{assert_static__ = 1/(e)};\
} while(0)
template int bit_copy(T&a ,U&b)
{
assert_static(sizeof(b)== sizeof(a));
memcpy(&a,&b,sizeof(b));
};
int main(){
int a = 0x2468;
double b;
bit_copy(a,b);
return 0;
}
#include
using namespace std;
template int bit_copy(T&a ,U&b)
{
static_assert(sizeof(b)== sizeof(a),"the parameters of bit_copy must have same width");
memcpy(&a,&b,sizeof(b));
};
int main(){
int a = 0x2468;
double b;
bit_copy(a,b);
return 0;
}
static_assert(sizeof(int) == 8,"This 64-bit machine should follow this!");
int main(){return 0;}
int positive(const int n){
static_assert(n>0,"value must > 0");
}
#include
using namespace std;
void Throw(){throw 1;}
void NoBlockThrow(){Throw();}
void BlockThrow() noexcept{Throw();}
int main(){
try{
Throw();
}
catch(...){
cout<<"found throw."<
struct A{
~A(){throw 1;}
};
struct B{
~B() noexcept(false) {throw 2;}
};
struct C{
B b;
};
int funA(){A a;};
int funB(){B b;}
int funC(){C c;}
int main()
{
try{
funB();
}
catch(...){
cout<<"caught funB."<
class Init{
public:
Init():a(0){}
Init(int d):a(d){}
private:
int a;
const static int b = 0;
int c = 1; // 成员,无法通过编译
static int d = 0; // 非整形或枚举的常量静态成员,无法通过编译
static const double e = 1.3;// 非整形或枚举的常量静态成员,无法通过编译
static const char * const f = "e";// 非整形或枚举的常量静态成员,无法通过编译
};
// 编译选项:g++ -c 2-7-1.cpp
// page-136
#include
using namespace std;
struct C{
C(int i):c(i){};
int c;
};
struct init{
int a = 1;
string b("hello"); // 无法通过编译
C c(1); // 无法通过编译
};
// 编译选项:g++ -std=c++11 -c 2-7-2.cpp
// page-138
#include
using namespace std;
struct Mem{
Mem(){cout << "Mem default , num "<< num << endl;}
Mem(int i):num(i){cout << "Mem default , num "<< num << endl;}
int num = 2;
};
class Group{
public:
Group(){cout << "Group default val :"<< val<
#include
using namespace std;
class Mem{
public:
Mem(int i):m(i){}
private:
int m;
};
class Group{
public:
Group(){} // 这里就不需要初始化data,mem,data成员了
Group(int a):data(a){} // 这里就不需要初始化mem,name成员了
Group(Mem m):mem(m){} // 这里就不需要初始化data,name成员了
Group(int a,Mem m,string n):data(a),mem(m),name(n){}
private:
int data = 1;
Mem mem{0};
string name{"Group"};
};
// 编译选项: g++ 2-7-4.cpp -std=c++11 -c
// page-141
#include
using namespace std;
struct People{
public:
int hand;
static People * all;
};
int main(){
People p;
cout<< sizeof(p.hand)<
class Poly;
typedef Poly P;
class Lilei{
friend class Poly;
};
class Jim{
friend Poly;
};
class HanMeiMei{
friend P;
};
int main()
{
return 0;
}
class P;
template class People{
friend T;
};
People PP;
People Pi;
/*
g++ -std=c++11 2-9-2.cpp -c
page 149
*/
#include
using namespace std;
#ifdef UNIT_TEST
#define private public
class Defender{
#endif
public:
void Defence(int x,int y){}
void Tackle(int x,int y){}
private:
int pos_x = 15;
int pos_y = 0;
int speed = 2;
int stamina = 120;
};
class Attacker{
public:
void Move(int x,int y){}
void SpeedUp(float ratio){}
private:
int pos_x = 0;
int pos_y = -30;
int speed = 3;
int stamina = 100;
};
#ifdef UNIT_TEST
class Validator{
public:
void Validate(int x,int y,Defender &d){cout <<"Defender Validate"<
#include
using namespace std;
template class DefenderT{
public:
friend T;
void Defence(int x,int y){}
void Tackle(int x,int y){}
private:
int pos_x = 15;
int pos_y = 0;
int speed = 2;
int stamina = 120;
};
template class AttackerT{
public:
friend T;
void Move(int x,int y){}
void SpeedUp(float ratio){}
private:
int pos_x = 0;
int pos_y = -30;
int speed = 3;
int stamina = 100;
};
using Defender = DefenderT; // 普通的类定义,使用int做参数
using Attacker = AttackerT;
#ifdef UNIT_TEST
class Validator{
public:
void Validate(int x,int y,Defender &d){cout <<"Defender Validate"<; // 测试专用的定义,Validator类称为友元
using AttackerTest = AttackerT;
int main()
{
Defender d;
Attacker a;
a.Move(15,30);
d.Defence(15,30);
a.SpeedUp(1.5f);
d.Defence(15,30);
Validator v;
v.Validate(7,0,d);
v.Validate(7,-10,a);
return 0;
}
#endif
/*
using Defender = DefenderT;这里用using来定义类型的别名,这个和使用typedef
的定义类型的别名是完全一样的,使用using定义别名是C++11中的一个新特性.
*/
/*
编译选项:g++ 2-9-4.cpp -std=c++11 -DUNIT_TEST
page 153
*/
#include
using namespace std;
class MathObject{
public:
virtual double Arith()=0;
virtual void Print()=0;
};
class Printable:public MathObject{
public:
double Arith()=0;
void Print(){
cout << "Output is:" << Arith() << endl;
}
};
class Add2:public Printable{
public:
Add2(double a, double b):x(a),y(b){}
double Arith(){return x+y;}
private:
double x,y;
};
class Mul3:public Printable{
public:
Mul3(double a ,double b,double c):x(a),y(b),z(c){}
double Arith(){return x*y*z;}
private:
double x,y,z;
};
// 编译选项:g++ 2-10-1.cpp -c
// page 157
struct Object{
virtual void fun()=0;
};
struct Base:public Object{
void fun() final;// 声明为final
};
struct Derived:public Base{
void fun(); // 无法编译通过
};
// 编译选项:g++ -c -std=c++11 2-10-2.cpp
// page 159
#include
using namespace std;
struct Base{
virtual void Turing() = 0;
virtual void Dijkstra()=0;
virtual void VNeumann(int g)=0;
virtual void DKnuth() const;
void Print();
};
struct DeriveMid: public Base{
void VNeumann(double g);// 接口被隔离了,曾想多一个版本的VNeumann,但是其实参数与基类中不一致,编译的时候却没有报错
};
struct DeriveTop: public Base{
void Turing() override; // 可以编译通过
void Dikjstra() override; // 无法编译通过,拼写错误,并非报的错中写的“没有重写”,应该报成“没有被正确重写”
void VNeumann(double g) override; // 无法编译通过,参数不一致,并非报的错中写的“没有重写”,应该报成“没有被正确重写”
void DKnuth() override; // 无法编译通过,常量性不一致,并非报的错中写的“没有重写”,应该报成“没有被正确重写”
void Print() override; // 无法通过编译,并非报的错中写的“没有重写”,应该是“不能对非虚函数进行重载”
};
/* 虚函数描述符override,如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译
如果不写override,编译器对
(1)函数名拼写错误;
(2)原型函数不匹配:参数类型错误,常量性等特征;
(3)重写非虚函数;
等是不会报错提醒的,有了override可以帮我们的编译器做一些辅助检查.
编译选项:g++ -c -std=c++11 2-10-3-1.cpp
我试了这个:g++ -c 2-10-3-1.cpp 也可以检查出效果
page 162
*/
#include
using namespace std;
struct Base{
virtual void Turing() = 0;
};
struct DeriveTop: public Base{
virtual void Turing() override{cout<<"First derive struct overrides the base's turing function and it must be done as it is defined as pure virtual function in the base class."<
#include
using namespace std;
template void TempFun(T a){
cout << a << endl;
}
int main (){
TempFun(1);// 1,示例化为TempFun(1)
TempFun("1");// "1",示例化为TempFun("1")
}
/*
编译选项:g++ 2-11-1-1.cpp
page 166
*/
void DefParm(int m = 3){} // C++98 编译通过,C++11编译通过
template // C++98 编译通过,C++11编译通过
class DefClass{};
template // C++98 编译不通过,C++11编译通过
void DefTempParm(){};
/*
编译选项:
g++ 2-11-1-2.cpp -c -std=c++98
g++ 2-11-1-2.cpp -c -std=c++11
page 167
*/
template class DefClass1; // 可以通过编译
template class DefClass2; // 不可以通过编译
template class DefClass3; // 可以通过编译
template class DefClass4; // 不可以通过编译
template void DefFunc1(T1 a ,T2 b);
template void DefFunc2(T a);
// 编译选项:g++ -c -std=c++11 2-11-2.cpp
// 编译选项:g++ -c -std=c++98 2-11-2.cpp
// page 168
template
void f(T t = 0,U i = 0)
void g(){
f(1,'c'); // f(1,'c')
f(1); // f(1,0),使用了默认模板参数double
f(); // 错误,T无法被推导出来
f(); // f(0,0),使用了默认模板参数double
f(); // f(0,0),自定义,可以推导出来
}
// 编译选项:g++ -std=c++11 2-11-3.cpp
// page 170