找回密码
 入驻
搜索
查看: 175972|回复: 3

Bjarne告诉我们,友元和虚技术可以这样用

[复制链接]
发表于 2007-5-31 13:54:09 | 显示全部楼层 |阅读模式
本例是根据我在蚂蚁上看到的C++之父Bjarne的防止类被继承的文章改写的,避开了他的美式语气,用尽可能简单的语句解释,用例也改成了一个有过程的例子,注释如有不妥,请指教

防止自己的类被别人继承
  1. #include <iostream.h>

  2. class Classb
  3. {
  4.      friend class Class1;          //声明Class1是友元类!
  5. private:                          //将Classb类的构造函数声明为私有!
  6.      Classb();
  7. };
  8. Classb::Classb()
  9. {}

  10. class Class1:public virtual Classb                    //Class1虚继承Classb
  11. {
  12. private:
  13.      int x;
  14.      int y;
  15. public:
  16.      Class1(){}
  17.      Class1(int x,int y)
  18.      {
  19.         this->x = x;
  20.         this->y = y;
  21.      }
  22. public:
  23.      int GetX(){return x;}
  24.      int GetY(){return y;}
  25.      int Get_Sub();
  26.      int Get_Dev();
  27. };
  28. int Class1::Get_Sub()
  29. {
  30. return x+y;
  31. }
  32. int Class1::Get_Dev()
  33. {
  34. return x-y;
  35. }

  36. class Class2:public Class1                //Class2继承Class1貌似合法  
  37. {
  38. public:
  39.      Class2();
  40. };
  41. Class2::Class2()
  42. {}
复制代码
  1. #include "h1.h"
  2. int main()
  3. {
  4. Class1 c1;
  5. Class1* c2=new Class1;             //无论是堆中还是栈中Class1的对象建立无误
  6. Class2 c3;                              //但是当Class2建立对象c3的时候,出错,原因是找不到Classb的构造函数,这样就防止了Class1被继承
  7. return 0;
  8. }
复制代码
到了后面,我们终于知道了Classb的设立是为了防止Class1被继承的,Class1虚继承Classb,Classb的构造函数是私有的,但是因为Class1被声明成为Classb的友元,所以Class1建立对象是合法的,但是继承Class1的Class2因为用的是虚继承,其构造函数的调用顺序是Classb->Class1,而Class2不是Classb的友元,因此不能访问到Classb的构造函数,所以对象无法建立,防止了Class1被继承!

经典程度:10分
灵活程度:10分
实用程度:4分(虚函数的调用是如此之快,没有使用的理由)

[ 本帖最后由 zkkpkk 于 2007-5-31 15:54 编辑 ]
发表于 2007-5-31 14:32:13 | 显示全部楼层
楼主很喜欢编程方面的东西哦。。不懂都做有什么小软件没啊。。

我最喜欢试用软件了。。
回复

使用道具 举报

 楼主| 发表于 2007-5-31 15:27:49 | 显示全部楼层
原帖由 幻猪 于 2007-5-31 14:32 发表
楼主很喜欢编程方面的东西哦。。不懂都做有什么小软件没啊。。

我最喜欢试用软件了。。

有,但是很少,一般是应付作业,我是做DLL的,类库方面的,面向对象服务派嘛
因为DLL是给开发者调用的(做积木的程序员帮堆积木的程序员提供积木嘛:lol ),所以面对普通用户不是那么地平易近人
不过你想用什么软件的话把需求给我我有能力的话一定帮做

[ 本帖最后由 zkkpkk 于 2007-5-31 15:56 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2007-5-31 16:01:42 | 显示全部楼层

编程论坛C++版的斑竹提供的对“虚”的分析

“这里的如果Usable不是虚继承基类的话DD dd;就不会错,虚继承决定了什么?!”把
  1. class Usable : public /*virtual*/ Usable_lock      //虚继承Usable_lock类
  2. {    // ...   
  3. public:        
  4.     Usable(){}   //这里改下,加上定义     
  5.     Usable(char*);        // ...   
  6. };  
复制代码

这样,代码就可以通过,就没有达到防止Usable 被继承的作用。
////////////////////////////////////////////////////////////////////////////////
先说说上面的代码,包括继承原理:
首先,把我们不想被继承的类作为一个派生类去继承一个没哟意义的Usable_lock类,注意,这个类显示的把构造函数
声明为私有,然后把Usable作为友员类,这就是关键。
再来,继承中派生类创建的过程:首先要调用父类的构造函数,即先建立一个父类的对象。
这里Usable类是公有继承,所以是访问不到私有的构造函数,但是作为友员是可以的,所以消除了这个限制。由此,我们的Usable类是可以被创建的。

到这里,看看为什么普通的非虚拟继承,能使dd的创建合法。
首先,按照我们先前说讲,DD类公有继承Usable类,创建dd对象的过程是先调用父类构造函数(Usable类构造函数),这一步合法,因为可以访问到Usable的构造函数。这时就要创建一个Usable对象,要创建Usable 对象,就要调用Usable 的父类构造函数,就来到Usable_lock类,开始我们说了,由Usable访问Usable_lock是没有问题的。所以这样一来,dd对象就被正确的创建了。他间接的访问过Usable_lock。

////////////////////////////////////////////////////////////////////////
下面说说BJ在这个例子中是怎样通过虚拟技术防止Usable类被继承的:
虚拟继承,通过在声明派生类继承父类时加上virtual来指定。
虚拟继承的作用:当系统碰到多重继承的时候保证继承类成员函数的唯一性。
怎么理解他的作用,看下面这个图1:
  1. class base //基类
  2. class derive1 : public base
  3. class derive2 : public base

  4. class derive3 : public derive1,public derive2
复制代码

这种情况下,derive3就同时拥有了两套base的函数。所以在调用时产生的模糊性会使程序出错。具体我就不谈那么多了。

解决这个问题,就用到了虚拟技术。
修改上面的代码 图2:
  1. class base //基类
  2. class derive1 : virtual public base
  3. class derive2 : virtual public base
  4. class derive3 : public derive1,public derive2
复制代码

采用虚拟继承的时候,在derive3中,一旦一次继承了base类,再次继承base的时候就会忽略重复的base类。所以保证继承类成员函数的唯一性。

///////////////////////////////////////////////////////////////////
在这个问题中,BJ大师用到的不是这个原理,而是由此产生的一个构造函数调用顺序问题。
在非虚拟继承中,比如图1中。在构造derive3时,其父类调用顺序为derive1-derive2-base;
然后在虚拟继承中。比如图2中。在构造derive3时,其父类调用顺序为base-derive1-derive2;

同样,这样的顺序,作用显而易见,是防止base被多次继承。

再回到我们最初的话题,在DD类创建对象dd时,最先被调用的是Usable_lock类的构造函数,但是,由于Usable_lock构造函数声明被私有,就出现不能访问的错误。由此,是不能创建DD对象的。用这个方法,完成了防止了Usable被继承。



//////////////////////////////////////////////////////////////////////
仓促中作了些对继承和虚拟继承的分析。不对的地方和需要完善的地方请指出。
很欣赏楼主这种思考精神

PS:这里所说的楼主就是我:loveliness
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 入驻

本版积分规则

QQ|Archiver|手机版|小黑屋|思明论坛

GMT+8, 2024-9-28 15:27 , Processed in 0.018362 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表