作者: 武汉华嵌教学部 张老师
以下小结了几个教学中同学们经常出现的理解错误,与大家分享。
1. 引用类型。很多初学者对引用这种数据类型存在误解,认为使用它时需要取地址,并且容易把它和指针搞混淆,比如下面的程序代码片段:
void fun(int& a,int& b)
{
int c=8;
&a=c ; //错误,a是引用类型的变量,不能对它取址做左值。
b=&c; //错误,b是引用类型的整形变量,不能将一个整形变量的地址赋值给它。
….
}
int main()
{
int m=5,n=6;
fun(&m,&n); //错误,m和n要传递给引用类型的形参,相当于要完成初始化赋值操作。
....
return 0;
}
其实,引用类型的很好理解,你只要记住以下三点:
1) 引用类型的变量是被引用变量的别名。
2) 引用类型的变量和被引用变量共同占用一块内存。
3) 引用类型一经初始化,就把它看成是个变量,对它的后续操作和对变量是一样的。
例如下面的程序代码片段:
int main()
{
int a=5;
int *p=NULL;
int& b=a; //正确,此时的b是“int&”这种引用类型,它是变量a的别名。
b=7; //正确,因为b和a共同占用一块内存,所以对b改变引起a的改变。
p=&b; //正确,b经初始化是一个变量,把b的地址赋值给指针p合情合理。
}
通过以上的说明,你应该对引用类型有了正确的理解。
2. typedef关键字。很多初学者认为typedef就是为一个数据类型起个别名,其实这是不准
确的,例如下面的一个语句:
typedef char array[80]; //这里难道是将a[80]作为char的别名?
显然不是,这里其实用typedef来说明此处的array是一个含有80个char字符的数组,我们可以用:
array a,b; //此时的a,b均是array这种类型,即含有80个char 字符的数组。
使用typedef可以使我们的定义更加的容易理解,特别是在解释一个非常复杂的函数原型时,例如linux下的信号处理函数:
void ( *signal (int signo,void (*func) (int) ) ) (int); // 这个原型你看得费力不?
此时,我们可以用:
typedef void sigfunc (int); //此时的sigfuc是一种函数指针类型
sigfunc *signal (int ,sigfunc *); //此时signal函数是带有两个参数,一个int类型,一个函数指针类型,并且它的返回类型是函数指针类型,而这个函数指针是指向一个无返回类型带一个int类型参数的函数。这样理解是不是清楚一点。
3. 内联函数。很多初学者认为内联函数就像宏一样,但比宏安全一点。其实这是不对的内联函数可以说是C++的一大优点,它有宏替换一样的效率,又有宏定义不具备的安全性,
C++的类的体内定义的那部分函数,编译器会默认是内联函数,而不管它加没有加inline这样一个关键字,例如:
class A
{
public:
int getsize() {return _size}
int getlength() {return _length}
}; //上面的两个成员函数都是内联函数。
另外,不是你定义一个内联函数,它就是内联函数,这是因为内联函数是由编译器决定,你向编译器申请一个内联函数,如果里面的代码量太大了的话,是申请不到的,因为内联函数的代码是放在符号表中的。在使用时直接进行替换。而符号表资源是有限的。
但是内联函数是函数,编译时期会去检查它的函数语法,形参类型是否正确等等。
4. this指针。很多人对this指针不理解,觉得它很诡异,当然也就存在很多误解,的确this指针比较的隐晦难懂。其实你只要记住以下几点就可以了:
1) this指针是编译器定义的一种指针变量,它存在于ecx寄存器中。
2) this指针的作用域是在类的体内。
3) this指针是通过成员函数调用时,传过去的。比如:
class a
{
void fun(){}
};
int main()
{
a obj;
obj.fun() //其实在这里编译器会自动把它转换成 fun(&obj),此时this就指向了obj了。
}
4) 一个类中的多个对象都是用this指针来指定的,this指针只有一个,但它是指针,可以指针不同的对象。
5) 当有一个基类和一个派生类对象时,若有且仅有派生类的一个对象,那么基类的this指针指向派生类对象。
5 const关键字。这个修饰词被很多人误解,有人认为它修饰的变量只读,也有人认为它不分配内存的,这些说法都是不准确的。其实const可以用来修饰非常多的类型还可以修饰函数,它在某些情况下不分配内存,而在另外一些情况分配内存。不管const修饰的是什么,你只要记住一点,const直接修饰的变量或函数,是针对这个变量本身的。比如下面的程序段代码:
int main()
{
int b=10;
const int size=100;
int array[size]; //类似于宏替换,在编译时直接替换,所以size是在符号表中不占内存
const int m[]={5,6,7,8}; //此时数组的各元素值是只读的,并且为这个数组分配的内存。
const int *p=&b; //此时只是修饰了p这个指针指向一个数据时,只能有只读属性操作。
b=12; //正确的,b可以做改变,因为const修饰的是指针。
int* const pn=&b; //正确的,也是修饰指针,但修饰的是指针存放的地址是只读的。
return 0;
}
记住const是个修饰词,一定要搞清楚它所修饰的对象是谁,修饰的对象的哪部分属性然后就把修饰的那部分属性看成是只读的就行了。
------分隔线----------------------------