OC与C++的区别参考汇总:

OCC++的区别参考汇总:

C++与OC同为面向对象设计语言,他们有很多相似的对象,但是由于两者属于不同的面向对象学派。因此两者之间的比较也乐此不疲。下面简要说说他们的区别:

        1.继承:Objective-C与同JavaSmalltalk一样不支持多重继承,而C++语言支持多重继承(从侧面可以说明多重继承的效率不高);

        2.函数调用:Objective-C通过互相传递消息实现函数调用,而C++直接进行函数调用

       3.定型:Objective-C是动态定型(dynamicaly typed)。所以它的类库比C++要容易操作。Objective-C 在运行时可以允许根据字符串名字来访问方法和类,还可以动态连接和添加类。而C++,对象的静态类型决定你是否可以发送消息给它。

        4.接口:Objective-C采用protocol协议(非正式和正式)的形式来定义接口,而C++采用虚函数的形式来定义接口。

        5.方法重载:c++中允许两个方法的名字相同,参数个数相同,但是参数类型不同,以及不同的返回值类型。而OC中不允许同一个类中两个方法有相同的名字,参数个数相同,参数类型不同。
总结 

1.C++存在多继承,OC没有,取而代之的有代理,类别,通知等较为常见的设计模式,从而导致思维方式的不同。

2.C++有公有和私有变量,OC没有私有变量一说,当需要访问OC类成员变量,就需要将类成员设置成类属性。

3.C++多态允许同一个类中两个方法有相同的名字,参数个数相同,参数类型不同。而OC不可以。

4.C++采用虚函数的形势定义接口,OC采用协议。


 c++与oc的对比 

我觉得最主要的区别就是,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对象被初始化好了。Hzh:隐式调用默认普通构造函数

第二种创建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;//直接用对象赋值,而非对象指针 //Hzh:赋值拷贝构造函数,运算符重载.


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


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拷贝的话,只拷贝了一个指针,这个指针指向一块内存,这块内存并没有拷贝。//Hzh:浅拷贝


CExample obj1;

obj1.Init(40);

CExample obj2 = obj1;

即它们将指向同样的地方,指针虽然复制了,但所指向的空间并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。当obj1删除pBuffer这块内存的时候,obj2的这块内存也没有了,obj2pBuffer指针指向的内存也被释放了。这中情况下就必须要重写拷贝构造函数,在这个函数中,把pBuffer这块内存也要复制。

CExample::CExample(const CExample& RightSides) //拷贝构造函数的定义

{

nSize=RightSides.nSize; //复制常规成员

pBuffer=new char[nSize]; //复制指针指向的内容 //Hzh:深拷贝

memcpy(pBuffer,RightSides.pBuffer,nSize*sizeof(char));

}

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

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


需要注意的一点就是:

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

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

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

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


C++的不同之处有:

O-C中所有的类都必须继承自NSObject

O-C中所有对象都是指针的形式。

O-Cself代替this

O-C使用id代替void*//Hzh:id既可用于函数参数类型也可用于函数的返回值类型,instancetype只可用于函数的返回值

O-C使用nil表示NULL

O-C只支持单继承。

O-C使用YES/NO表示TRUE/FALSE

O-C使用#import代替#include

O-C中用消息表示类的方法,并采用[aInstance method:argv]调用形式。

O-C支持反射机制

O-C支持Dynamic Typing, Dynamic BindingDynamic Loading

C++的相同之处有:

C共享的部分一致。

可以使用assert(BOOL), 一般用NSCParameterAssert(BOOL)代替。

O-C中的命名前缀说明:

NS-NextStep

CF-Core Foundation

CA-Core Animation

CG-Core Graphics

UI-User Interface

O-C中的消息特殊性:

调用消息的类可以不知道如何响应这个消息。如果它不知道如何处理这个消息,它会自动的将这个消息转给其他的类,比如它的父类。

调用消息的类可以是nil。在C++中,在使用类方法之前,我们都需要检查对象是否为空,所以在实现析构函数的时候,常会有如下的代码,如if (var) { delete var; }但是在objective c中,我们就可以直接写[var release];即使var == nil, 也不会有问题。

O-C中的函数声明格式有:

-/+ (return type) function_name;

-/+ (return type) function_name : (parameter type) parameter;

-/+ (return type) function_name : (parameter type) parameter1 otherParameter: (parameter_type) parameter2

以上参数说明:-表示一般函数,+表示静态函数。otherParameter是参数的别名(第一个参数的别名省略),在函数调用时方便指定。

O-C中的构造/析构函数

O-C中的init()/release()对应于C++的构造/析构函数。alloc()/dealloc()也就对应于C++newdelete,其中的dealloc()由于引用计数的自动调用而不用手动调用。

O-C中父类的init()/release()函数需要子类的手动调用。而且每次都必须调用。不同于C++的自动调用。

构造函数(- (id) init)调用形如:CSample* pSample=[CSample alloc] init];其中alloc(+ (id) alloc)是继承来的static函数,init是继承来的一般函数,如重写一般函数时,则相当于C++的覆盖(不带参数)或重载(带参数)

析构函数(- (void) release)将引用计数减1,当=0时父类的release()会自动调用dealloc(- (void) dealloc);

O-C没有数据成员时,可省略{},建议保留。

继承下来的方法,如:-(id) init可以头文件中省略,建议保留

O-C中只有数据成员的访问限制,没有方法的访问限制。

C++一样,数据成员有三种访问限制public, protected, private,缺省是protected

示例:@interface AccessExample: NSObject {

@public

int publicVar;

@protected

int protectedVar;

@private

int privateVar;

}

@end

方法的访问限制可通过Category实现

示例:

@interface MyClass

- (void) sayHello {

NSLog(@"Hello");

}

@end


@interface MyClass(Private)

- (void) kissGoodbye;

@end

O-C中没有类的静态变量,只有全局变量

O-C中的数组NSArray可以保存不同类型的数据。

O-C也支持run-time时的类类型检查

- (BOOL) isKindOfClass: classObj

用于判断该对象是否属于某个类或者它的子类

- (BOOL) isMemberOfClass: classObj

用于判断该对象是否属于某个类(这里不包括子类)

- (BOOL) respondsToSelector: selector

用于判断该对象是否能响应某个消息。这里,我们可以将@selector后面带的参数理解为C++中的函数指针。

注意:1)不要忘了@ 2@selector后面用的是(),而不是[]3)要在消息名称后面跟:,无论这个消息是否带参数。如:[pSquare respondsToSelector:@selector(Set: andHeight:)]

+ (BOOL) instancesRespondToSelector: selector

用于判断该类是否能响应某个消息。这是一个静态函数。

-(id) performSelector: selector :调用对象的selector方法。

conformsToProtocol 类似于respondsToSelector ,用于动态检查某个对象是否遵守某个协议。

Category:在没有源代码的情况下,为一个已经存在的类添加一些新的功能

只能添加新的方法,不能添加新的数据成员

Category的名字必须是唯一的

Protocol:相当于C++中的纯虚类

形如:@interface MyDate: NSObject <Printing> { } @end

使用:MyDate * dat = [[MyDate alloc] init];id<Printing> var = dat; [var print]

说明:我们首先声明了Printing 协议,任何遵守这个协议的类,都必须实现print 方法。在Objective C 中,我们通过<>来表示遵守某个协议。当某个类声明要遵守某个协议之后,它就必须在.m文件中实现这个协议中的所有方法。使用id<Printing> 作为类型,而不是象C++中的Printing* var

IBOutlet, IBAction: 这两个东西其实在语法中没有太大的作用。如果你希望在Interface Builder中能看到这个控件对象,那么在定义的时候前面加上IBOutlet,在IB里就能看到这个对象的outlet,如果你希望在Interface Builder里控制某个对象执行某些动作,就在方法前面加上(IBAction)

尽量避免在一行语句中进行两层以上的嵌套

消息转发:- (void) forwardInvocation: (NSInvocation*)anInvocation;

4扩展的关键字

编辑


@interface


类型声明,类似于c++中的class,区别在于Object c中的声明与实现是强制分开的,@interface关键字用于类型的声明,包括数据成员、方法声明、属性等。方法的参数传递采用中缀符的形式,利用分割参数名和被传递参数,类型的声明以@interface开头,以@end结束,通常一个类型的声明采用下面的结构:

@class someOtherObject //外部类型声明

@interfacesomeObject:NSObject //继承的类型

{

int i; //成员变量

}

-(id)someMethod:(int)someArg someOtherArgName:(int)someOtherArg; //对象的方法

+(id)someMethod:(int)someArg; //类方法

-(id)init; //初始化方法

@propertyint num; //属性

@end

@implementation


对应于@interface的类型声明,@implementation表示一个类型的实现过程,同样以@end结束,实现的格式通常如下:

@implementationsomeObject

-(id)someMethod:(int)someArg someOtherArgName:(int)someOtherArg

{

//实现代码

}

@synthesize num=i; //将属性与变量进行对应

@end

newalloc


Object C中的方法调用形式采用消息发送的方式,通常调用的形式如

[someObject someMethod:firstArg someOtherArgName:otherArg]

实例的初始化也采用消息发送的形式,可以简单的调用类型的new方法来获取一个实例对象,简单实例化的方法通常是:

someObject *obj = [someObjectnew]; //类的实例化

new方法的实际过程是调用allocinit方法,因此如果需要采用自定义的方法来初始化实例,则需要自己重写init方法,通常的初始化方式为:

someObject *obj = [[someObject alloc] init]; //采用无参数的init实例化

someObject *obj = [[someObject alloc] initWithArg:Arg]; //采用参数的实例化

@class


@class是一个前向引用声明,类似于C++中的friend友元声明,其作用是告诉编译器其后面的字段代表一个类型名称,尽管不知道类型的具体实现,但是只需要将其作为一个类型名称处理即可。通常在使用复合的结构时可以采用@class来减少头文件的相互引用,如果出现循环依赖,则需要依靠@class来避免引用的死循环。通常使用形式为:

@classsomeOtherObject;

@interfacesomeObject:NSObject

{

someOtherObject *obj;

}

@end

@property


尽管可以使用obj->arr的形式去强制读取对象的成员变量,但是良好的编程形式是对外界提供成员变量的读写接口。@property关键字提供了外界对成员变量的访问接口,其本质是为某一个属性提供setget操作。根据不同的需要,可以添加readonly(只读,相当于只添加get不添加set方法)或者readwrite(读写,如果不添加则为默认);还有三种赋值方式可选[2] assign(直接赋值,通常用于基本类型),retain(释放旧值,增加新的retaincount),copy(常用于字符串,生成一个新的拷贝)。通常使用的方式如下:

@interface someObject:NSObject

{

int i; //成员变量

}

@property (assign,readonly) int num; //属性

@end

@synthesize


@property对应,将一个外在属性与成员变量相关联,定义在@implementation中,如果属性名与变量名一致则可以省略变量名。常用方法:

@implementation someObject

@synthesize num=i;//如果属性名也为i,则可以直接写为 @synthesizei

@end

内存管理


Object C采用引用计数的方式进行内存管理,由于所有的对象都继承于NSObject,因此所有的对象都可以接受NSObject的三个方法:

-(id)retain;

-(void)release;

-(unsigned)retainCount;

retain方法将对象的引用计数加一并返回该对象,release将引用计数减一,retainCount方法返回对象当前的引用计数。当采用newalloccopy方法创建一个对象时,它的引用计数被置为1,如果程序中对该对象进行操作,则应根据需要,通过调用retainrelease方法来保证该对象在不需要的时候被清除。当一个对象的引用计数被置为0后,系统会自动向对象发送一个dealloc消息,将其占有的资源释放。通常情况下,如果一个对象的初始化过程调用了其他资源,则应该重写改对象的dealloc过程,保证在对象的销毁期正确释放这些资源。

为了更加方便的进行能存管理,cocoa中提供了一个自动释放池(autorelease pool)的概念,每一个类都继承了一个autorelease方法,当调用对象的autorelease方法时,改对象会被加入到开始创建的自动释放池中。当程序进行到不再需要自动释放池中的对象时,将自动释放池释放的时候会向池中的所有对象发送一个release消息,从而保证不再需要的对象被正确的释放。通常的用法如下:

NSAutoreleasePool *pool;

pool = [[NSAutoreleasePool alloc] init];

someObject * obj = [[someObject alloc] init];

[obj autorelease]; //加入自动释放池

//其他代码

[pool release]; //执行该语句时,系统会向池内所有的对象发送release消息;在这个例子中,如果对obj进行的其他retain操作和release操作保持一致的话,则会将obj的引用计数变为0,从而调用它的dealloc方法进行资源释放

Object C进行内存管理的3条规则是:

如果使用newalloccopy操作获得一个对象,则该对象的保留计数器值为1

如果通过任何其他方法获得一个对象,则假设该对象的保留计数器值为1,而且已经被设置为自动释放

如果保留了某个对象,则必须保持retain方法和release方法的使用次数相等。

类别


类别是为现有的类提供一个新的方法的方法,即使没有一个类的源代码,仍然可以向类中添加一个方法以方便使用。类别的主要目的有3个:将类的实现分散到多个不同的文件或框架中,创建对私有方法的前向引用,向对象添加非正式协议。

类别的声明方法:

@interfacesomeObject (someProtocal)

-(void)someMethod;

@end

类别的实现方法:

@implementationsomeObject(someProtocal)

-(void)someMethod

{

}

@end

@protocol


Object C中的协议类似于java中的接口,通过@protocol关键字定义一个或多个需要遵从协议的对象实现的方法,协议定义的方法:

@protocolsomeProtocol

-(void)someMethod;

@end

采用协议的方法是在类声明时使用尖括号注明其需要使用的协议:

@interfacesomeObject:NSObject <someProtocol>

在类实现时需要将协议中规定的方法都予以实现。

Object C 2.0增加了2个新的协议修饰符@optional@required,可以规定协议中的方法是否为必须实现的方法。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值