C++拾遗
原因:因为静态成员函数不传递this指针, 不和具体实例关联, 所以不能访问非静态member, 多用于callback。
2、类的静态函数不能声明为const、volatile、virtual;
static没有this指针,而这些的实现要求有this指针。
3、类的const成员函数不能改变对象的普通数据成员,但可以改变static和mutable的数据成员。
4、const对象只能调用const成员函数。
5、const可以用作函数重载的依据之一,和参数类型、返回值类型一样。
6、类的成员函数在调用会插入一个ClassName *Const this指针作为参数;而类的const成员函数在调用的时候会插入const ClassName *Const this指针作为参数。
7、没有指向引用的指针,因为引用并没有开放给外部的地址空间(不像普通的变量)。切记,把引用看作是变量的别名。
8、const引用是指不能通过引用改变变量的值,而非变量的值不能被修改;const 引用可以初始化为不同类型的对象或者初始化为右值(非const引用不可以):
int i=5;
const int &j=i;
i=4;//合法
j=4;//非法!!
———————–
int x=3;
const int& r=x; //正确
int& const r=x; //未定义,可能被编译器忽略,因为引用本来就是const(初始化后不能重新绑定)
——————–
const int ival = 1024;//ival为const
int &ref2 = ival;//错误!把一个const int 引用为非const类型
—————–
int& a =719;//错误
const int& a = 719;//正确,const引用可以初始化为右值
9、常量指针与指针常量:
char const *p //指向const字符的指针,这个const字符的值不能改变
const char *p //同上,也是常量指针
char * const p //指针本身是const ,不能改变指针的指向,但可以改变字符的内容,是指针常量
10、下列四种情况必须使用类的初始化列表:
a、初始化引用(reference)成员;
b、初始化 const 成员;
c、调用基类的构造函数,并且该基类的构造函数有参数时;
d、调用一个类成员的构造函数,并且它有参数时。
同时暗示着,如果有上面的四种情况,那么必须有构造函数来初始化它们。
11、iostream,输入输出流,流(stream)这个单词的意思是:试图说明字符是随着时间顺序生成或消耗的。
12、与其他变量不同,除非特别说明(extern),在全局作用域声明的 const 变量是具有文件作用域的局部变量。不能被其他文件访问。通过指定 const 为 extern(也即 extern const int a = 4;)可以跨文件作用域。
13、枚举成员是常量表达式,并且枚举成员值可以是不唯一的:
enum CivilNet
{
gemfield = 2, //2
leaflower,//3
syszux = 3, //3
civilnet_cn//4
};
14、const char name[8] = “Gemfield”; // error: Gemfield is 9 elements
15、一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组。
16、指针和 typedef
typedef string *pstring;
const pstring cstr;//string *const cstr而非const string *cstr
17、可使用跟在数组长度后面的一对空圆括号,对数组元素做值初始化:
int *gemfield = new int[10] (); //初始化为0
这种方法在const 对象的动态数组中就有用了:
const int *gemfield= new const int[100]();//必须初始化
不过这样的数组用处不大。
18、数组指针:
int *ip[4]; // 数组里面包含4个指针,指向int
int (*ip)[4]; // 指向一个包含有4个int的数组
注意[]的优先级要高。
19、后自增、自减运算符的优先级:
cout << *iter++ << endl;
由于后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。
20、零值指针的删除:
如果指针的值为 0,则在其上做 delete 操作是合法的,但这样做没有任何意义:
int *ip = 0;
delete ip; // ok
C++ 保证:删除 0 值的指针是安全的。
21、c++的强制类型转换:
dynamic_cast//无法正确转换那么会返回一个值是0的指针
const_cast //去掉const性质
static_cast//只使用于表达式的原类型与目标类型相适应的情况
reinterpret_cast //用于替代c中与实现相关的或不安全的强制转换
22、预处理器还定义了其余四种在调试时非常有用的常量:
__FILE__ 文件名
__LINE__ 当前行号
__TIME__ 文件被编译的时间
__DATE__ 文件被编译的日期
23、内联函数应该在头文件中定义,这一点不同于其他函数。
inline 函数可能要在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的。把 inline 函数的定义放在头文件中,可以确保在调用函数时所使用的定义是相同的,并且保证在调用点该函数的定义对编译器可见。
24、出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则称为重载函数。任何程序都仅有一个 main 函数的实例。main 函数不能重载。
如果两个函数声明的返回类型和形参表完全匹配,则将第二个函数声明视为第一个的重复声明。如果两个函数的形参表完全相同,但返回类型不同,则第二个声明是错误的。
函数不能仅仅基于不同的返回类型而实现重载。
仅当形参是引用或指针时,形参是否为 const 才能实现重载。
25、如果我们碰到复杂的类型声明,该如何解析它?例如:
char (*a[3])(int);
a到底被声明为什么东东?指针?数组?还是函数?分析时,从a 最接近(按运算符优先级)处开始。我们看到a最接近符号是[ ]——注意:*比[ ]的优先级低。a后既然有[ ],那么a是数组,而且是包含3个元素的数组。 那这个数组的每个元素是什么类型呢?a[3]是什么类型?是指针,因为它的前面有*. 由此可知,数组a的元素是指针。光说是指针还不够。对于指针,必须说出它指向的东东是什么类型。它指向的东东是什么,就看*a[3]是什么(a[3]是指针,它指向的东东当然是*a[3])了。继续按优先级观察,我们看到*a[3]后面有小括号,所以可以肯定*a[3]是函数。即数组a的元素是指向函数的指针。指向的是什么类型的函数?这很明显,是入参为int、返回值为char的类型的函数。
26、stringstream 对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。
int val1 = 512, val2 = 1024;
ostringstream format_message;
format_message << “val1: “<< val1<< “val2: ” << val2;//int->string
istringstream input_istring(format_message.str());
string dump;
input_istring >> dump >> val1 >> dump >> val2;//string->int
27、除了引用类型外,所有内置或复合类型都可用做元素类型。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:
元素类型必须支持赋值运算;
元素类型的对象必须可以复制。
转自:http://civilnet.cn/blog/article/610#more-610
1、类的静态函数不能访问非静态数据;
原因:因为静态成员函数不传递this指针, 不和具体实例关联, 所以不能访问非静态member, 多用于callback。
2、类的静态函数不能声明为const、volatile、virtual;
static没有this指针,而这些的实现要求有this指针。
3、类的const成员函数不能改变对象的普通数据成员,但可以改变static和mutable的数据成员。
4、const对象只能调用const成员函数。
5、const可以用作函数重载的依据之一,和参数类型、返回值类型一样。
6、类的成员函数在调用会插入一个ClassName *Const this指针作为参数;而类的const成员函数在调用的时候会插入const ClassName *Const this指针作为参数。
7、没有指向引用的指针,因为引用并没有开放给外部的地址空间(不像普通的变量)。切记,把引用看作是变量的别名。
8、const引用是指不能通过引用改变变量的值,而非变量的值不能被修改;const 引用可以初始化为不同类型的对象或者初始化为右值(非const引用不可以):
int i=5;
const int &j=i;
i=4;//合法
j=4;//非法!!
———————–
int x=3;
const int& r=x; //正确
int& const r=x; //未定义,可能被编译器忽略,因为引用本来就是const(初始化后不能重新绑定)
——————–
const int ival = 1024;//ival为const
int &ref2 = ival;//错误!把一个const int 引用为非const类型
—————–
int& a =719;//错误
const int& a = 719;//正确,const引用可以初始化为右值
9、常量指针与指针常量:
char const *p //指向const字符的指针,这个const字符的值不能改变
const char *p //同上,也是常量指针
char * const p //指针本身是const ,不能改变指针的指向,但可以改变字符的内容,是指针常量
10、下列四种情况必须使用类的初始化列表:
a、初始化引用(reference)成员;
b、初始化 const 成员;
c、调用基类的构造函数,并且该基类的构造函数有参数时;
d、调用一个类成员的构造函数,并且它有参数时。
同时暗示着,如果有上面的四种情况,那么必须有构造函数来初始化它们。
11、iostream,输入输出流,流(stream)这个单词的意思是:试图说明字符是随着时间顺序生成或消耗的。
12、与其他变量不同,除非特别说明(extern),在全局作用域声明的 const 变量是具有文件作用域的局部变量。不能被其他文件访问。通过指定 const 为 extern(也即 extern const int a = 4;)可以跨文件作用域。
13、枚举成员是常量表达式,并且枚举成员值可以是不唯一的:
enum CivilNet
{
gemfield = 2, //2
leaflower,//3
syszux = 3, //3
civilnet_cn//4
};
14、const char name[8] = “Gemfield”; // error: Gemfield is 9 elements
15、一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组。
16、指针和 typedef
typedef string *pstring;
const pstring cstr;//string *const cstr而非const string *cstr
17、可使用跟在数组长度后面的一对空圆括号,对数组元素做值初始化:
int *gemfield = new int[10] (); //初始化为0
这种方法在const 对象的动态数组中就有用了:
const int *gemfield= new const int[100]();//必须初始化
不过这样的数组用处不大。
18、数组指针:
int *ip[4]; // 数组里面包含4个指针,指向int
int (*ip)[4]; // 指向一个包含有4个int的数组
注意[]的优先级要高。
19、后自增、自减运算符的优先级:
cout << *iter++ << endl;
由于后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本。
20、零值指针的删除:
如果指针的值为 0,则在其上做 delete 操作是合法的,但这样做没有任何意义:
int *ip = 0;
delete ip; // ok
C++ 保证:删除 0 值的指针是安全的。
21、c++的强制类型转换:
dynamic_cast//无法正确转换那么会返回一个值是0的指针
const_cast //去掉const性质
static_cast//只使用于表达式的原类型与目标类型相适应的情况
reinterpret_cast //用于替代c中与实现相关的或不安全的强制转换
22、预处理器还定义了其余四种在调试时非常有用的常量:
__FILE__ 文件名
__LINE__ 当前行号
__TIME__ 文件被编译的时间
__DATE__ 文件被编译的日期
23、内联函数应该在头文件中定义,这一点不同于其他函数。
inline 函数可能要在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的。把 inline 函数的定义放在头文件中,可以确保在调用函数时所使用的定义是相同的,并且保证在调用点该函数的定义对编译器可见。
24、出现在相同作用域中的两个函数,如果具有相同的名字而形参表不同,则称为重载函数。任何程序都仅有一个 main 函数的实例。main 函数不能重载。
如果两个函数声明的返回类型和形参表完全匹配,则将第二个函数声明视为第一个的重复声明。如果两个函数的形参表完全相同,但返回类型不同,则第二个声明是错误的。
函数不能仅仅基于不同的返回类型而实现重载。
仅当形参是引用或指针时,形参是否为 const 才能实现重载。
25、如果我们碰到复杂的类型声明,该如何解析它?例如:
char (*a[3])(int);
a到底被声明为什么东东?指针?数组?还是函数?分析时,从a 最接近(按运算符优先级)处开始。我们看到a最接近符号是[ ]——注意:*比[ ]的优先级低。a后既然有[ ],那么a是数组,而且是包含3个元素的数组。 那这个数组的每个元素是什么类型呢?a[3]是什么类型?是指针,因为它的前面有*. 由此可知,数组a的元素是指针。光说是指针还不够。对于指针,必须说出它指向的东东是什么类型。它指向的东东是什么,就看*a[3]是什么(a[3]是指针,它指向的东东当然是*a[3])了。继续按优先级观察,我们看到*a[3]后面有小括号,所以可以肯定*a[3]是函数。即数组a的元素是指向函数的指针。指向的是什么类型的函数?这很明显,是入参为int、返回值为char的类型的函数。
26、stringstream 对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。
int val1 = 512, val2 = 1024;
ostringstream format_message;
format_message << “val1: “<< val1<< “val2: ” << val2;//int->string
istringstream input_istring(format_message.str());
string dump;
input_istring >> dump >> val1 >> dump >> val2;//string->int
27、除了引用类型外,所有内置或复合类型都可用做元素类型。引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:
元素类型必须支持赋值运算;
元素类型的对象必须可以复制。