最近再次拿起C++的书复习,然后觉得自己欠缺很多,我始终相信好记性不如烂笔头,所以我再次下定决心要把自己理解的写成文字,以后可以回过来看看。好了,废话不多说,这是我这段时间第一篇文章,鼓励下自己(o(∩_∩)o )!
我是根据自己的能力写的,有不足和错误的地方请大家指正,并最好通过邮箱或在本博客留言告诉我,我会非常感谢。
对象传值到函数:传值、传递指针、引用。
1. 传值
先来看个简单的例子,
#include <iostream>using namespace std;class A{public: void print() { cout<<"Class A!"<<endl; } };void test1(A a){ a.print(); }int main(int argc, char *argv[]){ A a; test1(a); return 0;}//运行结果:Class A!
嗯,确实这个代码很简单,也很普通。如果我这里代码修改下:
编译也是正常的,结果也是一样。我传进去的确是一个整型,你没看错。这里涉及到一个知识点,通过类的单参数构造函数进行隐式类型转换。显示的转换就是这样:
test1(A(a));
当然这个在需要的时候是很好,但是在某些情况下却是一种麻烦了,例如:
class String {
String ( int n ); //本意是预先分配n个字节给字符串
String ( const char* p ); // 用C风格的字符串p作为初始化值
//…
}
下面两种写法比较正常:
String s2 ( 10 ); //OK 分配10个字节的空字符串
String s3 = String ( 10 ); //OK 分配10个字节的空字符串
下面两种写法就比较疑惑了:
String s4 = 10; //编译通过,也是分配10个字节的空字符串
String s5 = ‘a’; //编译通过,分配int(‘a’)个字节的空字符串
s4 和s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。
#include <iostream>using namespace std;class A{public: virtual void print() { cout<<"Class A!"<<endl; } };class B : public A{public: void print() { cout<<"Class B!"<<endl; } void print2() { cout<<"Class B2!"<<endl; }};void test1(A a){ a.print(); //a.print2(); 编译错误 }int main(int argc, char *argv[]){ B b; test1(b); return 0;}//运行结果:Class A!
俄,到这里已经觉得一个函数传值有这么多名堂呢?其实我这里的也只是其中一部分我觉得,如果还有其他要注意的请留言啊,不要自己藏着拿出来分享。
2. 传递指针
#include <iostream>using namespace std;class A{public: virtual void print() { cout<<"Class A!"<<endl; }};class B : public A{public: void print() { cout<<"Class B!"<<endl; } void print2() { cout<<"Class B2!"<<endl; }};void test1(A *a){ a->print(); //a->print2(); //编译错误 }int main(int argc, char *argv[]){ B b; test1(&b); return 0;}//运行结果:Class B!
嗯?运行结果不同了。嗯,是的。到这里可以思考了。上面参数值传递是对象拷贝的,拷贝的时候基类的结构和派生类不一样,基类的空间结构小于派生类,派生类对象拷贝到基类那么必然切掉了一些,切掉可想而知是派生类新定义的成员。而指针只是指向原来那片空间,尽管指针类型是基类,基类是可以向派生类转换的隐式。我的理解是这样。故指针还是保留着派生类所有成员。
3. 引用
同样的,将指针的修改成引用。
#include <iostream>using namespace std;class A{public: virtual void print() { cout<<"Class A!"<<endl; }};class B : public A{public: void print() { cout<<"Class B!"<<endl; } void print2() { cout<<"Class B2!"<<endl; }};void test1(A &a){ a.print(); //a->print2(); //编译错误 }int main(int argc, char *argv[]){ B b; test1(b); return 0;}//运行结果:Class B!
嗯,效果和指针一样,但是有点不同,它不像指针那样临时创建个新的指针,它的参数名称就是该对象的别名,其实就是这个对象,只是取了个小名。就是有个孩子叫毛阿敏,小名叫小毛,其实就是同一个人。指针传递就是去北京最出名的烤鸭掉,只要知道了地址,那么谁都可以到达吃到香喷喷的烤鸭,不管他是阿三还是阿四,就像指针P1或P2,只要得到了这个地址。
还有指针和引用的区别:
指针操作比较繁琐,不注意就会出错。
如:
指针需要->,而引用就像平常的一样使用就行了。
一般定义指针变量都要赋值,防止程序出错。指针不赋初值,编译器也是编译正常,不会告诉你,需要赋值更加好。而引用的话,不赋初值会编译错误,在一定程度上提高程序的正确性和安全性。如:
char *p; //可以不赋值
char &p;//编译错误
char *p1=0; //编译正确
char &p2=(*p1);//编译正确
同时在函数参数传递的时候也是这样,可以确保传进来的不是空值。
总结:内置对象传值很简单,非内置的话要注意单参数构造函数的隐式转换,基类与派生类在传递的时候注意要使用引用或指针,个人感觉引用较好。还有就是指针和引用最主要的区别就是指针指向数据内存空间,而引用则是就是它本身只是取了个别名。
好了,我要总结的就这些了,请大家指正。
参考文献:
[1]Scott Meyers.More Effecitve C++.
[2]http://www.cnblogs.com/cutepig/archive/2009/01/14/1375917.html
[3]http://www.cnblogs.com/foxlee/archive/2005/08/02/205566.html
联系客服