第二章-保证稳定和兼容性
2.1 保持与C99兼容
-
预定义宏
-
__func__预定义标识符__func__可以显示当前的函数名字- 还可以放在类或者结构体中
#include <iostream> class TestClass { public: TestClass () : name (__func__) {} const char *name; // failed 由于在参数声明时,__func__还未被定义 // TestClass () {} // const char *name = __func__; }; int main (int argc, char *argv[]) { TestClass tc; std::cout << tc.name << std::endl; return 0; } // out // TestClass
-
_Pragma操作符
#pragma once与头文件的防止重复包含的功能一样,在C++11中是保留了_Pragma,所以在C++11中,#pragma once=_Pragma("once")
-
变长参数的宏定义以及
__VA_ARGS__
在C99标准中,可以这样使用#define PR(...) printf(__VA_ARGS__),例如一个简单的LOG例子
#include <iostream>
#define LOG(...) { \
fprintf(stderr, "%s: line %d: \t", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
}
int main (int argc, char *argv[]) {
int a = 7;
LOG("a = %d", a);
return 0;
}
// out
// test.cpp: line 11: a = 7
2.2 long long整型
long long整型有两种:long long和unsigned long long。在C++11中,标准要求long long整型可以在不同平台上有不同的长度,但至少有64位。
2.3 扩展的类型
比如UINT、__int16、u64、int64_t,等等。这些类型有的源自编译器的自行扩展,有的则是来自某些编程环境(比如工作在Linux内核代码中),不一而足。而事实上,在C++11中一共只定义了以下5种标准的有符号整型:
signed char, short int, int, long int, long long int
2.4 宏__cplusplus
常见的就是在c与c++混合编写的代码中,经常用这个宏定义。
第二个就是可以判断编译器是否支持c++11#if __cplusplus < 201103L ......
2.5 静态断言
在通常情况下,断言就是将一个返回值总是需要为真的判别式放在语句中,用于排除在设计的逻辑上不应该产生的情况。比如一个函数总需要输入在一定的范围内的参数,那么程序员就可以对该参数使用断言,以迫使在该参数发生异常的时候程序退出,从而避免程序陷入逻辑的混乱。
- 运行时与预处理时的断言
在C++中,标准在<cassert>或<assert.h>头文件中为程序员提供了assert宏,用于在运行时进行断言。
在C++中,程序员也可以定义宏NDEBUG来禁用assert宏。这对发布程序来说还是必要的
#error,下面的代码,预处理时就会报错,可以提示一些信息
#ifndef _HRAD_H_
#error "asdf."
#endif
-
静态断言
static_assert编译时报错
static_assert(常量表达式,提示字符串)
eg,
static_assert(1 == 2, "a must equire b");.编译报错:test.cpp:11:5: error: static assertion failed: a must equire b
2.6 noexcept
针对异常的关键字
2.7 快速初始化成员变量
- 类内部初始化变量,就地初始化,
- 初始化列表的效果总是优先于就地初始化的,也就是说
{}>=or()
2.8 非静态成员的sizeof
class A {
public:
int a;
};
int main (int argc, char *argv[]) {
// c++98编译不过,c++11编译通过
std::cout << sizeof(A::a) << std::endl; // result is 4
// c++98,可以这样获得非静态成员的大小
std::cout << sizeof(((A *)0)->a) << std::endl; // result is 4
return 0;
}
2.9 扩展的friend语法
友元可以无视类中成员的属性。无论成员是public、protected或是private的,友元类或友元函数都可以访问,这就完全破坏了面向对象编程中封装性的概念。因此,使用friend关键字充满了争议性
- 使用上
class A {
friend class Poly; // C++98 pass, C++11 pass
friend Poly; // C++98 fail, C++11 pass
};
- 关于模板的友元
TODO
2.10 final 和 override
- final关键字的作用是使派生类不可覆盖它所修饰的虚函数。
-
引入了虚函数描述符override,如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译。
-
总结 关于 static const final override 默认参数 的在类内外的使用
class Base { public: virtual void final_test() = 0; virtual void override_test() = 0; }; class ImpBase : public Base{ public: // static放在声明中 static void static_test(); // const声明和实现都需要加上 const void const_test() const; // final和override在函数声明中加 virtual void final_test() final; // final和override在函数声明中加 virtual void override_test() override; // 默认参数在声明和实现只能存在一处,如果两处都有,那么两个默认参数到底是哪个呢? void default_test(int a = 10); static int a; }; // 类外初始化静态成员 int ImpBase::a = 50; void ImpBase::static_test() { std::cout << "static_test" << std::endl; } const void ImpBase::const_test() const { std::cout << "const_test" << std::endl; } void ImpBase::final_test() { std::cout << "final_test" << std::endl; } void ImpBase::override_test() { std::cout << "override_test" << std::endl; } void ImpBase::default_test(int a) { std::cout << "default_test" << std::endl; }
2.11 模板函数的默认模板参数
TODO
2.12 外部模板
TODO