C++ vs Objective C
2013-01-01 13:24
357 查看
Are you a game developer transitioning from Cocos2d iPhone to Cocos2d-X? From Objective C to C++?
C++ used to be my language. It was all I wrote computer games in for over 10 years. There's a certain level of power, control and efficiency in using C++.
When the iPhone came out, the Objective C language became a hot topic. I was so excited about the thought of writing games for iPhone that I forced myself, despite wariness at
Now, after nearly three years of making games in Objective C with Cocos2D-iPhone, I've discovered Cocos2D-X and unearthed a whole new love for C++.
If Objective C is an automatic transmission car, then C++ is a manual.
One might argue that the automatic car is superior because it's easier. However, that one hasn't had the experience of clutching into neutral across a gravelly patch to avoid spinning the tires.
So, C++ has more speed and control, yet it requires a greater level of skill from the programmer.
For example, C++ saves execution time by not checking pointers before you dereference them. This increases the speed of your game and your level of control, yet it requires basic assertion skills.
With Objective C, you can safely send messages to nil objects (though this comes at the cost of slightly slower program execution).
In C++, if you try to dereference a null pointer, you'll trigger a runtime error and have to fix your code up.
Behind the scenes, ObjC basically implements a nil object which essentially
returns zero for any method call. This makes programming a little safer and easier. However, it also can allow bugs to go unnoticed.
C++ doesn't check a pointer before dereferencing it. As illustrated above, if the node is null, then C++ will execute the setPosition function given a null
One solution is to use an
assert which only gets compiled into non-distribution builds. If the expression being asserted evaluates to false, then the program aborts. If you've got a debugger attached, then it will pause on the assert line so you can see exactly where the code went
wrong.
Since assert is typically defined as a macro, one of the pros to using it is that in distribution builds (or any build which defines NDEBUG), the macro evaluates to nothing. Essentially, the compiler doesn't even include it. This gives you the security of
assertions in debug builds and the raw speed of no assertions in distribution builds.
Essentially this makes C++ a little more efficient and a bit easier to catch bugs at the cost of the programmer having to be a bit more pragmatic.
You see the difference in readability?
Objective C is a bit easier to read because the 2nd parameter to the addChild method is clearly a z value. In C++, it's anyone's guess what "1" means.
Modern day Integrated Development Environments (IDEs) like Xcode mitigate the issue when you are writing code because of auto-completion. You start typing addChild and it gives you the parameter types and names. This makes it clear what the parameters are
when you are writing the code. However, if you take some time off from the project and come back later, you might be a little perplexed when you glance at that addSprite call and wonder about the second parameter.
You can make C++ more readable by changing up your style a little bit. Like this:
We've already talked about how C++ is a
faster than Objective C. But what about portability? This is where C++ shines.
C++ is simply more portable than Objective C. It can be natively compiled on many platforms including the presently popular Android OS.
When it comes to Android, it is technically possible to compile ObjC if you upgrade the default NDK's GCC compiler, but there's a catch or two. You need all those Foundation classes.
Remember
Thankfully, there's projects like
Cocotron which aim to do just that. However, when it comes down to areas that are Android-specific, like input and sound, you need a cross-platform library. Something that implements that stuff for you so you don't have to go rewriting it for each and every
platform.
That's why C++ and Cocos2dx are so awesome. Cocos2dx handles the platform-specific stuff and does the bulk of it in portable C++.
Beyond speed, portability and readability, we get into more specific differences between the languages, like Objective C's Class and
C++ doesn't have the equivalent of a Class type. It does have runtime type information (RTTI) and can roughly convert a pointer into a string containing the object's class with
typeid. However, since the results can vary per platform, the solution is not exact enough to be relied upon.
Objective C's Class type makes creating objects from strings quite nice. Consider the following:
This illustrates the elegance of ObjC's Class type and one possible workaround in C++.
You can also see in the above code we are using ObjC's
reasons not to use either.
In C++, you have to redefine goToSleep in Child's interface if you want to override. In Objective C, you can just be lazy and override it in the implementation.
The reason C++ forces a programmer to redefine functions that will be overridden is because it makes the job of the compiler easier. The compiler doesn't have to go checking up the class hierarchy for mystery methods.
In the above example, we saw the use of the C++
In Objective C, all method calls are essentially virtual. This makes it a bit easier on the programmer, but it comes at a possible
performance decrease.
Again, C++ comes through on the manual transmission car analogy. You can specify virtual or non-virtual, as appropriate.
In C++, you can allocate objects on the stack. Stack allocation is
faster than heap allocation and also guarantees that the
destructor will be called when the object goes out of scope, even if an exception has been thrown.
Here's an example:
In Objective C, it's
not possible to overload operators. You can workaround that by creating worded methods:
However, this makes Objective C a bit wordy when it comes to some things:
re-indexed because of a header file change):
In C++, there is the concept of public and private, however the privates have to be declared in the public interface.
If you really don't want to declare a private function in the public interface, you can work around by using static functions in the implementation (which is similar to the Objective C blank category strategy mentioned above).
Categories are pretty neat because a class can be extended anywhere, including the .h, the .m or some other place.
C++ doesn't technically have the ability to extend a class. However, it does have
multiple inheritance.
Objective C doesn't have default parameters, but it can get by with a multiple method workaround:
Keep in mind that you can always use both. In fact, you can mix them together with
Objective C++.
You just rename your implementation file with the .mm extension. That tells your compiler to use Objective C++ and enables either Objective C, C++ or a mix of both to be used.
Objective C++ is a common thing. As you can see in the example above, it's required to respond to iOS & Mac app notifications and launch Cocos2d-X in the same method.
Got questions? Leave a comment below.
Stay tuned. We are writing the next chapter in this free online book. If you'd like, you can
subscribe to be notified when we release new chapters.
C++ used to be my language. It was all I wrote computer games in for over 10 years. There's a certain level of power, control and efficiency in using C++.
When the iPhone came out, the Objective C language became a hot topic. I was so excited about the thought of writing games for iPhone that I forced myself, despite wariness at
[[funny foreign] syntax], to learn Objective C and begin writing a game. Boy was I surprised when I came to love Objective C's simple elegance and powerful Foundation classes.
Now, after nearly three years of making games in Objective C with Cocos2D-iPhone, I've discovered Cocos2D-X and unearthed a whole new love for C++.
C++ is a Manual Transmission Car
If Objective C is an automatic transmission car, then C++ is a manual.
One might argue that the automatic car is superior because it's easier. However, that one hasn't had the experience of clutching into neutral across a gravelly patch to avoid spinning the tires.
So, C++ has more speed and control, yet it requires a greater level of skill from the programmer.
For example, C++ saves execution time by not checking pointers before you dereference them. This increases the speed of your game and your level of control, yet it requires basic assertion skills.
Sending Messages to nil Objects (or Dereferencing null Pointers)
Here we have one of the most fundamental differences between ObjC and C++.With Objective C, you can safely send messages to nil objects (though this comes at the cost of slightly slower program execution).
// in Objective C CCNode* node = nil; // this will not crash, it will just do nothing [node setPosition:ccp(10,10)];
In C++, if you try to dereference a null pointer, you'll trigger a runtime error and have to fix your code up.
// in C++ CCNode* node = nullptr; // nullptr introduced in C++11 // this will crash node->setPosition(ccp(10,10)); // using a safeguard, this will not crash if(node) node->setPosition(ccp(10,10)); // using an assertion will trigger a debuggable error assert(node); node->setPosition(ccp(10,10));
Behind the scenes, ObjC basically implements a nil object which essentially
returns zero for any method call. This makes programming a little safer and easier. However, it also can allow bugs to go unnoticed.
C++ doesn't check a pointer before dereferencing it. As illustrated above, if the node is null, then C++ will execute the setPosition function given a null
thispointer. When a member variable is accessed via the null
thispointer, your program crashes.
One solution is to use an
assert which only gets compiled into non-distribution builds. If the expression being asserted evaluates to false, then the program aborts. If you've got a debugger attached, then it will pause on the assert line so you can see exactly where the code went
wrong.
CCNode* node = nullptr; // this will pause execution when debugging assert(node);
Since assert is typically defined as a macro, one of the pros to using it is that in distribution builds (or any build which defines NDEBUG), the macro evaluates to nothing. Essentially, the compiler doesn't even include it. This gives you the security of
assertions in debug builds and the raw speed of no assertions in distribution builds.
Essentially this makes C++ a little more efficient and a bit easier to catch bugs at the cost of the programmer having to be a bit more pragmatic.
Readability
Here's another fundamental difference. Objective C is inherently more readable than C++ because method parameters are built into the name of the method. Consider:// Objective C [layer addChild:sprite z:1];
// C++ layer->addChild(sprite, 1);
You see the difference in readability?
Objective C is a bit easier to read because the 2nd parameter to the addChild method is clearly a z value. In C++, it's anyone's guess what "1" means.
Modern day Integrated Development Environments (IDEs) like Xcode mitigate the issue when you are writing code because of auto-completion. You start typing addChild and it gives you the parameter types and names. This makes it clear what the parameters are
when you are writing the code. However, if you take some time off from the project and come back later, you might be a little perplexed when you glance at that addSprite call and wonder about the second parameter.
You can make C++ more readable by changing up your style a little bit. Like this:
int z = 1; layer->addChild(sprite, z);
Speed and Portability
We've already talked about how C++ is a
faster than Objective C. But what about portability? This is where C++ shines.
C++ is simply more portable than Objective C. It can be natively compiled on many platforms including the presently popular Android OS.
When it comes to Android, it is technically possible to compile ObjC if you upgrade the default NDK's GCC compiler, but there's a catch or two. You need all those Foundation classes.
Remember
NSObject,
NSStringand
NSArray? Those are all implemented fully and awesomely on the Mac, but not Windows. All those have to be reimplemented in a cross-platform way.
Thankfully, there's projects like
Cocotron which aim to do just that. However, when it comes down to areas that are Android-specific, like input and sound, you need a cross-platform library. Something that implements that stuff for you so you don't have to go rewriting it for each and every
platform.
That's why C++ and Cocos2dx are so awesome. Cocos2dx handles the platform-specific stuff and does the bulk of it in portable C++.
Beyond speed, portability and readability, we get into more specific differences between the languages, like Objective C's Class and
idtypes.
The Class and id Types
Objective C has a nifty thing called the Class type. It allows you to take the class of an object and store it in a variable.C++ doesn't have the equivalent of a Class type. It does have runtime type information (RTTI) and can roughly convert a pointer into a string containing the object's class with
typeid. However, since the results can vary per platform, the solution is not exact enough to be relied upon.
Objective C's Class type makes creating objects from strings quite nice. Consider the following:
// Objective C NSString* string = @"Hammer"; Class class = NSClassFromString(string); id object = [[class alloc] init];
// C++ Tool* tool = nullptr; std::string string = "Hammer"; if( string == "Hammer" ) tool = new Hammer;
This illustrates the elegance of ObjC's Class type and one possible workaround in C++.
You can also see in the above code we are using ObjC's
idtype. It is essentially a pointer to any object type. The rough equivalent in C++ is
void*, however there are many
reasons not to use either.
Laziness
Let's say we have a parent class called Parent, a subclass of it called Child, and Parent has a method called goToSleep.In C++, you have to redefine goToSleep in Child's interface if you want to override. In Objective C, you can just be lazy and override it in the implementation.
// Objective C @interface Parent : NSObject -(void) goToSleep; @end @interface Child : Parent // woo! don't have to redefine goToSleep @end @implementation Parent -(void) goToSleep {} @end @implementation Child -(void) goToSleep {} @end
// C++ class Parent { public: virtual void goToSleep(); }; class Child : public Parent { public: // goToSleep has to be redefined // if it is to be overridden virtual void goToSleep(); }; void Parent::goToSleep() {} void Child::goToSleep() {}
The reason C++ forces a programmer to redefine functions that will be overridden is because it makes the job of the compiler easier. The compiler doesn't have to go checking up the class hierarchy for mystery methods.
Virtual
In the above example, we saw the use of the C++
virtualkeyword. When
virtualis used, it specifies to use the function in the lowest class of the hierarchy first (for example Child's goToSleep as opposed to Parent's goToSleep).
In Objective C, all method calls are essentially virtual. This makes it a bit easier on the programmer, but it comes at a possible
performance decrease.
Again, C++ comes through on the manual transmission car analogy. You can specify virtual or non-virtual, as appropriate.
The Stack
In Objective C, you can only allocate objects from the heap.In C++, you can allocate objects on the stack. Stack allocation is
faster than heap allocation and also guarantees that the
destructor will be called when the object goes out of scope, even if an exception has been thrown.
Here's an example:
// Objective C // Heap allocations only Tool* tool = [[Tool alloc] init];
// C++ // Sweet! We've got fast, reliable stack allocations Tool tool;
Operator Overloading
In C++ you can overload operators. For example, if you were programming a Vector object, you could overload the addition operator so that Vectors could naturally be added together.// C++ class Vector { const Vector operator+(const Vector& v) const { return Vector(x + v.x, y + v.y, z + v.z); } } // this '+' calls the overloaded operator+ // isn't it nice? Vector v1,v2,v3; v3 = v1 + v2;
In Objective C, it's
not possible to overload operators. You can workaround that by creating worded methods:
// Objective C v3 = [v1 addVector:v2];
However, this makes Objective C a bit wordy when it comes to some things:
// Objective C NSString* a,*b; if( [a isEqualToString:b] ) [self doSomething];
// C++ std::string a,b; if( a == b ) doSomething();
Privates
Objective C doesn't technically have private methods. However, the workaround using a blank category in the implementation is quite nice because the private method doesn't have to be declared in the public interface (and hence your project automaticallyre-indexed because of a header file change):
// In an Objective C header file (.h) @interface Something : NSObject // See? No private method @end
// In the implementation file (.m) // Extend the Something interface with a category // (Blank categories denote private stuff) @interface Something () // a blank category -(void) privateMethod; @end
In C++, there is the concept of public and private, however the privates have to be declared in the public interface.
If you really don't want to declare a private function in the public interface, you can work around by using static functions in the implementation (which is similar to the Objective C blank category strategy mentioned above).
Class Extensions
As we saw in the above example, Objective C can extend a class with a category.Categories are pretty neat because a class can be extended anywhere, including the .h, the .m or some other place.
C++ doesn't technically have the ability to extend a class. However, it does have
multiple inheritance.
Default Parameters
C++ has one final bit of coolness to discuss: default parameters. A parameter to a function can be given a default, so that supplying it when calling the function is optional.// C++ class Something { void doSomething(int i, float f = 0.0f) {} }; Something s; // can be called with or without the f parameter s.doSomething(5); s.doSomething(5, 1.0f);
Objective C doesn't have default parameters, but it can get by with a multiple method workaround:
// Objective C @interface Something : NSObject -(void) doSomething:(int)i; -(void) doSomething:(int)i withF:(float)f; @end @implementation Something -(void) doSomething:(int)i { [self doSomething:i withF:0.0f]; } -(void) doSomething:(int)i withF:(float)f { } @end Something* s = [[Something alloc] init]; // either method can be called, however // two separate methods have been implemented [s doSomething:5]; [s doSomething:5 withF:1.0f];
Conclusion: Mixing C++ & ObjC
So that's about it for the primary differences between ObjC and C++.Keep in mind that you can always use both. In fact, you can mix them together with
Objective C++.
You just rename your implementation file with the .mm extension. That tells your compiler to use Objective C++ and enables either Objective C, C++ or a mix of both to be used.
// In the file AppDelegate.mm @implementation AppDelegate -(void) applicationDidFinishLaunching:(NSNotification*)aNotification { // Do some Objective C stuff window = [[Window alloc] initWithContentRect:...]; // Now switch to C++ and launch Cocos2dx cocos2d::CCApplication::sharedApplication().run(); } @end
Objective C++ is a common thing. As you can see in the example above, it's required to respond to iOS & Mac app notifications and launch Cocos2d-X in the same method.
Got questions? Leave a comment below.
Stay tuned. We are writing the next chapter in this free online book. If you'd like, you can
subscribe to be notified when we release new chapters.
相关文章推荐
- C++ vs Objective C
- 从 C++ 到 Objective-C[转自DevBean's World]
- iOS SDK开发时,有关OC和C++混编造成其它类错误的问题(Compile Sources As Objective-C++)
- iphone开发之C++和Objective-C混编 如何在xcode中用C++的STL
- C++ 网站 VS下载网站
- 从 C++ 到 Objective-C(10):实例化(续)
- C++(10):VS2015使用某些函数显示不安全需要末尾添加_s的解决办法
- vs2013 c++小代码运行完了不退出的方法
- EAFP in Python VS. LBYL in Java/C++
- Cython入门.VS.C++
- VS2015 C#调用C++ 托管代码无法调试问题排查
- C++ 内存管理之五(数组 vs 指针)
- Java调用vs环境下C++编写的动态链接库
- carbide C++ vs eclipse
- Xcode中Objective-C和C++混编的实现 (二)
- vs2008下C++开发问题汇总
- #define vs const in Objective-C 用 #define 还是 const
- 【C++】修改VS2013的默认堆栈大小
- cocos2d-x项目过程记录(Objective-C转C++)
- PAT程序设计考题——甲级1036( Boys vs Girls ) C++实现