有下面的一个CPerson类:
class CPerson
{
public:
void show()
{
cout<<"I am a people"<<endl;
}
};
在实际编程中,我们经常会看到一个类型有下面两种不同的使用方式:
CPerson s1;
CPerson *s2 = NULL;
s2 = new CPerson();
s1.show();
s2->show();
delete s2;
那么这两者在实际的使用中到底有何差别呢,下面从不同的方面来剖析一下。
调用方式上的不同
首先二者最明显的区别就是调用方式上的不同,对象使用" . "操作符调用,而指针使用" -> "操作符调用,且指针在调用时需要先用new来分配空间,且用完后必须手动delete掉。如不想手动delete也可使用智能指针。
内存空间上的不同
二者的类型决定了它们在内存上的分布不同,一个是对象类型,一个是指针类型。对象类型在创建时就已为对象分配好内存空间,用的是内存栈,是个局部的临时变量,作用域在该函数体内,随函数的结束被释放。
指针变量在创建时也是在内存栈,里面的值是对象的地址,当用new操作符时会在内存堆上分配一个空间,即存储实际的对象内容,此时的指针变量里的值即为刚刚分配的内存地址。所以为什么要用delete释放呢?这是因为内存栈里的变量会随着函数的结束而释放,内存堆里的内容需要用户手动释放,所以当函数调用结束时,指针变量会被释放,如果不先delete的话,内存堆里的内容就会找不到地址,也就"无人看管"了。所以在实际使用中一定要记得用完后delete,若是数组,则是delete[]。
作为函数参数的不同
类的对象和指针都可作为函数参数传递,这其中还可以有一个引用,代码如下:
void func(CPerson object)
void func(CPerson* object)
void func(CPerson &object)
那么这几种方式有何区别呢?下面来一一分析一下。
1: void func(CPerson object)
这种函数是非常不建议的,因为函数参数压栈时,对object进行了复制(还记得拷贝构造函数吗),所以函数对object的操作实际上是对新的对象空间进行的操作,不会影响原对象空间。由于不必要的拷贝对象是十分浪费时间的,也没有意义,我们完全可以用函数func(const Cobject& object);来代替,同样能保护对象的只读性质。
2:void func(CPerson object)
这种方式是将类指针作为参数,函数压入参数时实际上复制了指针的值(其实指针可以看作一个存放地址值的整形),实际复制的指针仍指向原对象的空间,所以func函数对该指针的操作是对原对象空间的操作。
3: void func(CPerson &object)
这种方式和传指针类似,但函数压入参数时实际上复制了object对象的this指针,其实this指针不是一个真正存在的指针,可以看作是每个对象的数据空间起始地址。func函数中对this指针的操作,实际上也是对原对象空间的操作。
不管值传递,引用传递啊乱七八遭的什么东西,反正调用函数时都是会复制参数的,只是不同的是复制的是地址,还是整个对象空间的区别而已。
相同的,函数CPerson func(CPerson& object);在return CPerson对象时,同样会进行构贝构造。这些隐藏的对象复制都是不需要的,我们可以改为CPerson& func(CPerson& object);或是CPerson* func(CPerson& object);这样,在return时,就只是对指针(地址)的复制而已。在不是特殊的情况下,不要将整个对象作为参数,也不要返回整个对象。
类指针实现多态
还有一个显著区别就是类指针可以实现多态,通过分类指针调用子类对象,下面详细说明。
C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
1:用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。
2:存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。
3:多态性是一个接口多种实现,是面向对象的核心,分为类的多态性和函数的多态性。
4:多态用虚函数来实现,结合动态绑定.
5:纯虚函数是虚函数再加上 = 0;
6:抽象类是指包括至少一个纯虚函数的类。纯虚函数:virtual void fun()=0;即抽象类!必须在子类实现这个函数,即先有名称,没有内容,在派生类实现内容。
下面看一个具体例子:
class CPerson
{
public:
virtual void show()
{
cout<<"I am a people"<<endl;
}
};
class CStudent:public CPerson
{
public:
void show()
{
cout<<"I am a student"<<endl;
}
};
int main()
{
CStudent stu;
CPerson *per = &stu;
per->show();
system("pause");
return 0;
}
输出的结果为:
可以看到父类指针指向子类对象后,调用的是子类的show函数,注意多态的实现需要在函数前加virtual修饰,使其为虚函数,否则调用的还是父类的,总之要实现多态,类指针和虚函数缺一不可。关于多态的详细分析具体可以参考http://www.cnblogs.com/cxq0017/p/6074247.html
通过以上对类对象和类指针不同方面的分析,我们在知道在什么时候应该使用类对象,什么时候使用类指针比较好。
感谢您的阅读!