c++与oc的对比

来源:互联网 发布:淘宝快递打印机设置 编辑:程序博客网 时间:2024/06/06 09:23

我觉得最主要的区别就是,c++中的对象可以是动态创建的(使用new来创建,返回对象的地址),也可以是直接的创建对象(如:A a;就是直接创建)。

所以在c++中就有了 值传递 与指针传递的区别。在Java中是没有的,oc中也是没有的,因为java与oc创建的对象都相当于是创建的对象的指针,而不能直接的创建对象本身,都是通过这个指针去访问对象的。


比如,我在c++中创建一个B对象,可以用2种方式:

1,

class A:  //学生对象

{

public: 

    int  id;

    string name;

    int age;

    string sex;

};

第一种创建B的方法:

class B:

{

public:

    int classId; //班级编号

    A a; //学生对象数组 

} //这种方式创建,是直接创建的A a对象,B b;那么当B对象创建的时候,就为a对象分配了空间,也就是a对象被初始化好了。


第二种创建B的方法:

class B:

{

public:

    int classId; //班级编号

    A  *a;  //学生对象数组的指针 

} //这种方式创建,只创建了一个A对象的指针,所有指针都是4个字节,这个时候其实a对象是个null,并没有分配内存。只有当a = new A();的时候才为a分配了内存。

总结:

可以看出,第一种方法就是非动态的创建内存的例子,使用A a;直接的分配内存。第2种方法就是动态分配内存的例子,使用A *a;当需要初始化a的时候再用new为它分配内存。

很显然,第2种方法要好得多。当需要的时候再分配内存,可以提高内存的使用效率。而objective-c就是这种方法的忠实拥护者,在oc中只能动态的创建内存,这也是oc的动态特性之一。

我们假设A对象占20个字节,

如果按照第一种B类的写法。B b;创建B对象,b占用的内存空间是20 + 4,也就是24个字节。

如果按照第二种B类的写法。B b;创建B对象,b占用的内存空间是4 +4,也就是8个字节,这是因为A *a是一个指向a对象的指针,只占4个字节,这个时候,b.a是null,只有当在需要使用b.a的时候,为a对象初始化。b.a = new A();。这也就是oc中的懒惰初始化,也叫延迟初始化。

在oc中只能用第二种方法初始化,第一种方法是没有的。

只有当类中有指针的时候,才能延迟初始化,

char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
int nSize;
};只有这种情况下,pBuffer会在需要的时候去动态的申请内存。


再来谈谈c++的拷贝构造函数:

在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):
1) 一个对象作为函数参数,以值传递的方式传入函数体;
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
3) 一个对象用于给另外一个对象进行初始化(常称为复制初始化
务必要注意区分这3种情况与OC种的区别,在OC中是根本不存在这3种情况的。因为oc中只能创建对象的指针,是不能直接创建对象的。上面的3种情况都是针对与直接操作一个对象的。

比如:

B getBObj(B bb)

{

    return bb;

}


{

B b1;

B b2 = b1.getObj(b1); //直接传对象,非对象指针

//传进去的b1是实参,bb其实是调用拷贝构造函数拷贝出来的b1的一个副本,当返回bb的时候,b2接受的是bb对象的一个拷贝副本,因此内存中有b1,bb,b2对象,当getObj调用完毕,bb对象被释放,内存中还有b1,b2两个对象。所以注意:bb并不是b1对象,b2并不是bb对象就可以了。

b2 = b1;//直接用对象赋值,而非对象指针


正常情况下,编译器会创建隐式的拷贝构造函数,那什么时候需要重写拷贝构造函数呢?

class CExample
{
public:
CExample(){pBuffer=NULL; nSize=0;}
~CExample(){delete []pBuffer;}
void Init(int n){ pBuffer=new char[n]; nSize=n;}

private:
char *pBuffer; //类的对象中包含指针,指向动态分配的内存资源
int nSize;
};

这中情况下,如果直接调用默认的拷贝构造函数,那么拷贝的过程中,pBuffer拷贝的话,只拷贝了一个指针,这个指针指向一块内存,这块内存并没有拷贝。

CExample obj1;
obj1.Init(40);
CExample obj2 = obj1;
即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。当obj1删除pBuffer这块内存的时候,obj2的这块内存也没有了,obj2的pBuffer指针指向的内存也被释放了。这中情况下就必须要重写拷贝构造函数,在这个函数中,把pBuffer这块内存也要复制。
CExample::CExample(const CExample& RightSides) //拷贝构造函数的定义
{
nSize=RightSides.nSize; //复制常规成员
pBuffer=new char[nSize]; //复制指针指向的内容
memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));
}

只有这样重写拷贝构造函数之后,拷贝的时候就没有问题了。

这中情况就类似于objective-c中的对象拷贝。对象深拷贝的话,就必须要实现copy方法,在这个方法中重新真正的copy,所以c++中的默认拷贝构造函数就类似oc中的浅拷贝,也就是指针拷贝。


需要注意的一点就是:

oc中虽然不能直接的创建对象,但是oc中函数调用,以及返回的时候,传入的参数一样会拷贝一份出来,只不过这个拷贝是一个指针,而不是拷贝的一个对象。返回的时候一样是拷贝的一个副本,这个副本是指针。

正是因为c++中有直接创建对象与创建对象指针的区别。所以才产生了值传递,与地址传递的区别。它可以传递一个对象,也可以传递这个对象的地址。如果传递的是对象本身,就是值传递。如果传递的是对象的指针,就是指针传递。其实指针传递也是传递的值,传递的是变量的地址值。

但是在oc与java中,只能传递对象的地址。所以就不用区分上面的情况了。

其实c++中指针传递也是传递的值,传递的是变量的地址值,这个地址值是一个对象的首地址。

 来自:http://blog.csdn.net/itianyi/article/details/9046231

0 0
原创粉丝点击