C++基础细节2(一)

2014-11-24 08:35:55 · 作者: · 浏览: 2
1.关于引用和指针
概念上,引用(&)并不是对象,而是一个已经存在的对象的别名;引用不可以重新绑定到另外一个对象,因此引用必须初始化。(类比const,一经定义就不能修改,所以必须初始化,是同样的道理。)
引用和指针都是实现了其他对象的间接访问。不同的是:指针本身就是一个对象,允许对指针进行赋值和拷贝;指针无需在定义时赋初值。
对于引用的概念,通过这段代码加深印象:
int ival=12;
int *p=&ival;
int &refval=ival;
int *p1=&refval;
int &refval=ival;中的&是代表引用声明符号;而int *p1=&refval;的&则代表取地址。
如下图的watch中所示,可以看出p和p1这两个指针的值(所存放的地址值0x0039F1D8),以及这两个指针所指向的值(12)是完全一样的(其实有点废话,既然两个指针都是指向同一个地址,自然指向的值是一样的),也就是ival和它的引用refval是等价的。
注意:虽然指针p1初始化为&refval,而&refval和&ival这两个值是不一样的,也就是refval和ival是存放在内存中的不同地址上,但是int *p1=&refval这句初始化之后,p1指针上存的值其实并不是refval的地址,而是refval所引用的变量ival的地址。因此,这里就更明确了:引用的作用就相当于代言者,这个代言者所说所做的一切都代表了原始对象,与引用自身无关。
由于引用不是对象,所以不存在指向引用的指针。我想基本上这也上面那句int *p1=&refval之后,p1的值竟然是ival的地址的概念上的辅证。
但是存在指针的引用。
2.关于const
如果利用一个对象去初始化另外一个对象,则他们是否是const都无所谓。常量特性仅仅是用于限定其初始化之后不可修改。
如果想在多个文件中共享const对象,必须在变量的定义之前添加extern关键字。
3.C风格字符串
C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法,按此习惯书写的字符串存放在字符数组中并用空字符('\0')结束。
char ca[] = { 'C', '+', '+' };
cout << strlen(ca) << endl;
上面的示例中,ca虽然是一个字符数组,但是它并没有以'\0'结束,因此这段代码输出的结果不可知。strlen函数在执行的时候可能沿着ca在内存中的位置不断向前寻找,直到遇到'\0'才结束。
而只有这样:
char ca[] = { 'C', '+', '+', '\0' };
cout << strlen(ca) << endl;
才能保证输出的结果是3.
再定义两个字符数组来说明:
char ca1[] = "string 1";
char ca2[] = "string 2";
由于在使用数组的时候,其实真正使用的是指向数组的首元素的指针。因此我们不能使用if(ca1
我们必须使用strcmp进行字符串比较操作;使用strcpy和strcat进行字符串的拷贝和连接操作,而且在strcpy和strcat函数的使用的时候,我们要非常仔细的检查字符数组的容量:
char sumStr[40];//注意数组容量,调试的时候又想起了最近看到的关于“烫烫烫烫”的冷笑话
strcpy(sumStr, ca1);
strcat(sumStr, "-");
strcat(sumStr, ca2);
(ps:在vs2013上进行编译的时候,编译器直接告诉我:'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead
char sumStr[40];
strcpy_s(sumStr, ca1);
strcat_s(sumStr, "-");
strcat_s(sumStr, ca2);
需要说的是:strcpy_s、strcat_s是VS后续版本中微软新推出的更安全的函数,并非标准库里面的。所以还是建议使用string以保证可移植)
4.函数返回类型
函数返回类型不能是数组类型或者函数类型,但是可以是指向数组或者函数的指针。
5.通过引用避免拷贝
针对函数形参,拷贝大的类类型对象或者容器时效率比较低,甚至有的类型(比如IO类型)根本不支持对象拷贝,这种情况就必须使用引用参数。另外,为了避免在函数内修改实参,我们可以使用常量引用。
bool cmp_length(const string &s1, const string &s2)
{
return s1.size() > s2.size();
}
另外,比较好的习惯是:&,*符号和参数名写在一起,不要和类型连写,以免理解上的误会。
6.类
构造函数:
构造函数不能使用const。只有在类没有声明任何构造函数的时候,编译器才会自动生成默认无参构造函数。因此,一旦我们定义了其他默认构造函数,那么除非我们在定义一个无参数的构造函数,否则类将没有默认构造函数。如果类包含有内置类型或者复合类型的成员,那么只有在这些成员全部都赋予了类内的初始值的时候,这个类才适合于使用合成的默认构造函数。C++11新标准允许使用=default来要求编译器生成默认构造函数。
大多数情况下,使用构造函数初始化列表,或者提供参数,在构造函数的函数体中使用赋值语句在效果上没有什么区别。但是针对const、引用,这种则必须通过构造函数初始化来处理。
如下这段处理就是错误的:
复制代码
class A
{
public:
A()
{//提示报错:常量成员b和引用成员c没有提供初始值
b = 0;//错误,只读根本不能修改
c = 0;//没有初始化
}
private:
int a;
const int b;
int &c;
};
复制代码
正确的方式是使用构造函数初始化列表:
复制代码
class A
{
public:
A(int x) :b(x), c(x)
{
}
private:
int a;
const int b;
int &c;
};
复制代码
友元(friend):
友元的声明仅仅是制定了访问的权限,而并不是一个通常意义上的函数声明。如果我们希望类的用户能够调用某个友元函数,那么我们必须在友元生命之外再专门这个函数进行一次声明。虽然许多编译器并不强制限定友元函数必须在使用之前在类