现在的位置: 首页 > 综合 > 正文

c++的对象分布

2013年09月17日 ⁄ 综合 ⁄ 共 1698字 ⁄ 字号 评论关闭

如果要研究C++的对象模型,大家潜意识都想知道的是,C++比C好在哪里?又比C差在哪里?

我们主要就是想从C++的对象模型里找到后一个答案。前一个答案在软件工程中是毫无疑义的,面向对象的优越性要比C语言里一堆数据结构+和一堆可能与它们相关的函数,可读性、可用性好很好,对开发大型软件工程,需要几百人开发一个项目来说,C++好太多了。看看JAVA或者python程序员们,他们为什么可以一直站在巨人的肩膀上,想完成任何一个功能都超级方便的调用大师们以前写好的package/API,借用各种设计模式,应用级别程序员们可以非常EASY的使用复杂的设计,一些只有高级C程序员才能掌握的东东。当然,JAVA的很多特性也导致不适应核心服务器的开发,比如它的垃圾回收机制。

OK,闲话少叙,在看对象模型前,先看几个C++与C语言的典型不同之处。

1、自然是类的定义了,最大的改变就是类把数据结构与方法捆到一起了,可读性上提升巨大。对成员变量和成员方法,有5种类型:static member, nonstatic member, static function, nonstatic function, virtual function.

2、继承,这里很有许多细节了,核心解决问题就是动态绑定,也就是virtual关键字。virtual出现的唯一原因就是为了解决继承机制,否则struct里引入方法就足够了,class出现就是为了这。virtual关键字解决了子类实例和父类实例的一些特殊关系,考虑以下场景:软件工程中,很喜欢每个模块专注于自己的事,尽量忽略与自己无关的实现,这样,很可能会用一个父类指针,该指针太可能指向多种不同的子类了,但是现在,使用这个抽象父类指针的模块不想关注细节,当它调用对象的某个方法时,到底是调用父类的方法还是子类的方法呢?动态绑定这个特性就是,开发者可以决定这一点,当你用virtual关键字申明父类方法时,如果子类重定义了该方法,如果这个指针实际指向的是某子类对象,那么调用的方法一定是该子类方法的实现。

举个例子吧,就像什么析构函数总喜欢写成virtual?这个例子应该容易说明virtual的玩法。一段简单的代码:

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4.   
  5. class Father  
  6. {  
  7. public:  
  8.     int m_fMember;  
  9.     Father(){m_fMember=1;}  
  10.     ~Father(){cout<<m_fMember<<endl;}  
  11. };  
  12.   
  13.   
  14. class Child : public Father{  
  15. public:  
  16.     int m_cMember;  
  17.     Child(){m_cMember=2;}  
  18.     ~Child(){cout<<m_cMember<<endl;}  
  19. };  
  20.   
  21.   
  22. int main(int argc, char** argv)  
  23. {  
  24.     Father* pObj1 = new Child();  
  25.     delete pObj1;  
  26.     Child* pObj2 = new Child();  
  27.     delete pObj2;     
  28.     return 0;  
  29. }  

这段代码的结果是1 2 1,啥意思呢?就是说,如果不用virtual函数,是没有执行期绑定一说的,比如pObj1这个指针,其实它是Child对象,但是在释放时,~Child()方法并没有被调用,仅调用了~Father方法。为什么呢?因为没有用virtual,就是编译期绑定,当你在编译时gcc/g++只知道pObj1是个Father对象,所以在delete时就去调用Father的析构了。而如果定义成virtual ~Father时,结果就是一定会析构Child,这就是为什么析构函数都要用virtual,因为没人知道会不会有子类继承,否则一旦继承,发生这样的事,析构函数里万一释放了些资源,比如SOCKET,比如memory,那就是资源泄露了。

抱歉!评论已关闭.