如果大家熟悉java的话应该知道java中有一种类不能被继承,那就是final类。这种类有很多用处,尤其是在大的项目中控制类的继承层次。使子类数量不至于爆炸。在使用了多继承的类层次中这也是防止出现菱形继承层次结构的一个好办法。要实现一个不能被继承的类有很多方法。51Testing软件测试网OtDi;D 主要的思路就是使子类不能构造父类的部分,这样子类就没有办法实例化整个子类。这样就限制了子类的继承。所以我们可以将父类的构造函数声明成为私有的,但是这样父类不就不能实例化。我想可以添加一个静态帮助函数来进行构造。虽然这样很简陋。但是这的确是一种解决方法。51Testing软件测试网M%M/i3P?8pL+E
oFLz6di#ot0n"B%}%c0 可是如果只有这个方法能够解决,那么C++实在是太不灵活了。而且这也不值得写一片文章出来!有没有办法解决上面的方法中的那些问题呢?51Testing软件测试网&Q[7}cG`^%s
51Testing软件测试网e,l~
k5rrV*EX 我们可以利用友员不能被继承的特性!51Testing软件测试网5BV#[2w1D)~h+Z\
ZA)Q"Y C)` x,jl0
首先假设已经有一个类CXX。这是某一个类层次的分支,我们现在要从CXX继承一个Final子类CParent来,也就是CParent不能够被继
承。我们可以充分利用友员不能被继承的特点,也就是说让CParent是某一个类的友员和子类,CParent可以构造,但是CParent的子类
CChild确不能继承那个友员特性,所以不能被构造。所以我们引入一个CFinalClassMixin。51Testing软件测试网P#wX|t9X:R }
51Testing软件测试网(M^,p9V`;L$k3_ 我们对这个类的功能是这么期望的:
DsD;uI:y1`[051Testing软件测试网4Kw'T'R
nLJ6n&x@ 任何类从它继承都不能被实例化51Testing软件测试网3s
Ce6Ih2P
51Testing软件测试网5TOT:J'F-n K 同时这个类本身我们也不希望它被实例化。
$x`P~+iX0"nJGz+q#h6B'O0 如何实现这个类那?很简单!那就是实现一个构造函数和析构函数都是private的类就行了。同时在这类里面将我们的CParent声明为友员。代码如下:
rm*Z1y m%@3l0class CFinalClassMixin 0E"N7yD?*Y0 {51Testing软件测试网5_)E v
n`1}:m friend class CParent; 4^2FEL5l(b0b|0 private:51Testing软件测试网,c3jTp
en!YwO|/{j CFinalClassMixin(){}51Testing软件测试网 J8_IOP^W+Dx ~CFinalClassMixin(){} 2|(^'p)S%Q0 };51Testing软件测试网h-G
C9m/h;} Y //我们的CParent代码应该如下: T r.@"`[p9aC'w0 class CParent:publicCXXX !`.} c(b;?PN*Ec0 { D{e}^8A0 public: xo1Q2m/{#j,mXC+b0 CParent(){}51Testing软件测试网Zr(eF
W!R1XQ*^ ~CParent(){}51Testing软件测试网9@ ]B9df.GM }; |
a:dh@'n0 它是从CXXX扩展的一个类(注,此时它还是能够被继承)。现在我们需要它不能被继承,那么只要将代码改成51Testing软件测试网@
P9F*jc5A9K;]
class CParent:public CFinalClassMixin, public CXXX Ei-@scz(P'Rwp0 {51Testing软件测试网b
yWI(kcX public:51Testing软件测试网'ti+SL0t CParent(){}51Testing软件测试网"UgB5`Cb#I.J ~>CParent(){}51Testing软件测试网*rS/K^t?` }; |
51Testing软件测试网\XLh)d0Y 就行了。现在从CParent继承一个子类试试51Testing软件测试网Y,MW7t7PJ1G;d
|b$rDtZ.Y\0 class CChild:public CParent{};
&[,ZRh b:Kz\H09cCH o;r']
mNh0 编译一下代码试试,发现:竟然没有作用!!51Testing软件测试网U/o||~h
51Testing软件测试网NRQl:U2k/T'SS,t 现在再回想一下我们这么操作的原因,也就是这个方案的原理,那就是让父类可以访问Mixin类的构造函数,但是子类不能访问。51Testing软件测试网8f#~jmv)zZ@7x
r[+VHf%^0H.|r0 现在看看我们的代码,发现父类是CFinalClassMixin类的友员,可以访问它的构造函数。因为友员不能继承,所以CChild不能访问CFinalClassMixin的构造函数。所以应该不能被实例化。
AKXF0o02{Tk^)RK7v~M0 CChild的确不能访问CFinalClassMixin的构造函数,但是它却不必调用它!我想这就是问题的原因所在。CChild是通过CParent来构造CFinalClassMixin的,所以这个友员对他并没有什么用处!
0i"uOV7d0o}@B*ZcW9pgP~0 现在问题找到了。要解决很简单。只要让CChild必须调用CFinalClassMixin的构造函数就行了,怎么才能达到目的呢?51Testing软件测试网
ix!k!R.AYfF
1R0C d%E;{
b2L0 还记得虚继承吗?虚继承的一个特征就是虚基类的构造函数由最终子类负责构造!所以将CParent从CFinalClassMixin继承改成从CFinalClassMixin虚继承就可以了。代码如下:
1G/[yVJEM}
q051Testing软件测试网H|s[5D?!r/`t,Z$ED5]{0class CParent:virtual public CFinalClassMixin, public CXXX51Testing软件测试网9K0@ kr,j#P2x {51Testing软件测试网,o6@ad}.A2j3C public: *B
n9M,]a~0 CParent(){}51Testing软件测试网9|1N1k;K'e
B*v8d9DC CParent(){}51Testing软件测试网1NAn? \^!m }; |
51Testing软件测试网KC|j c(l6n q 现在试试,行了。
3Ege*doO051Testing软件测试网qo4Xs;Oz 但是可能有些人会对多继承心有余悸!但是我们这里并没有必要这么担心!为什么?因为我们的CFinalClassMixin类是纯的!pure! 也就是说它根本没有成员变量!那么我们就根本不用担心多继承带来的最大问题。菱形继承产生的数据冗余。以及二义性。51Testing软件测试网Gu$I%RH|'n+^
)_WiT%Xwv Sc0 现在还有个不足!那就是我们不能每次使用这个CFinalClassMixin类就在里面加上对某个类的友员声明啊!这多麻烦啊! 虽然不是什么大问题,但是我觉的还是要解决,因为我充分信任C++!51Testing软件测试网+WO7L9r7R9q?f
51Testing软件测试网,S A-}.~!Q;L^/U^m 解决的方法也很简单!那就是使用模板!具体描述就省略了,给出代码大家一看就知道了51Testing软件测试网:Fg8q @'}/h
-?u@d!?;I8J0 下面是我得测试程序的完整代码(其中的CFinalClassmixin已经改成模板)51Testing软件测试网 l&g&jkp Q
,lF
lxB7Dq}rY051Testing软件测试网RO&h
f x5G{Y{
// finaltest.cpp : Defines the entry point for the console application.51Testing软件测试网?5M%o(uH$`/S2Q [ //51Testing软件测试网aJ/_
H:m5` #include "stdafx.h"
Zh+x#]O*[}0 #include <iostream> J
oD.FGY&yE:}sc0 using namespace std; *A
et7o
W$T4{Pr0Y0 template<class T> @9d4j_?1C
\a0 class CFinalClassMixin51Testing软件测试网&}G;ZO
b0D { -Y}M'ZT&u4yD0 friend T; C_n8ygym u0 private: ;cvX#E_C)Rl8R4b~0 CFinalClassMixin(){} M#\5lK@(NFa:D*J+@0 ~CFinalClassMixin(){}51Testing软件测试网gl(e3\UiPTMz5P8f };51Testing软件测试网a7ldH8p
TY nu class CXXX RH@#SNCv
pt2y0 {51Testing软件测试网[+L6l[v uZ public: stt5drQ"sY0 CXXX(){cout << "I am CXXX" << endl;}51Testing软件测试网3`@O9\
x(W`L ~CXXX(){}51Testing软件测试网,r,aI"qH%w[ };
@.^b"z5o+s^.n(U0 class CParent:virtual public CFinalClassMixin<CParent>, public CXXX 1oz2fbAj?0 { djd.l$y8oas0 public:51Testing软件测试网L0r6PLF8xN:Xo?? CParent(){} 8`!V[z/s0] a"EM&S0 ~CParent(){} 1j%f
\ u)j.`1ht0 };51Testing软件测试网m
m+["v1I/iA
s.x:{ class CChild:public CParent{};51Testing软件测试网 OFXot[~xs int main(int argc, char* argv[])51Testing软件测试网SYM8Q+]mc/E0@ J {51Testing软件测试网 H ?$l;}1L o
AQ CParent a; // 可以构造51Testing软件测试网.xL+YV
l6^"ql a //CChild b; //不能构造51Testing软件测试网sp_h/TF0VC*o3s return 0;51Testing软件测试网M9F5GV0Ag } |
k
L;ZVRf`*d;w;oT0 现在只要对不想被继承的类加入一个CFinalClassMixin混合类做父类就行了。
+y4z!Ed3DY:QH:L051Testing软件测试网
N8j9iC!Zo(m 通过限制构造函数,我们就达到了限制继承的目的。但是这对有些还是个例外,比如全是静态函数的类。这些类本身就不需要构造。所以我们对它没有办法。但是在大多数情况下,一个全是静态函数的类多少暗示了程序本身的设计可能是需要斟酌的。51Testing软件测试网&MM4M$X+D+r`)A
/S'ZXZ9_ R0 其实这只是Mixin类(混合类)使用的一个小小例子。还有很多其他的用处,比如UnCopiale等等。就不多说了。我想说明的是大家可能对
多继承比较反感。但是过分否定也是得不偿失的。现在对多继承到底应不应该使用还处在争论阶段。我觉得一个方法是否使用得当,关键还是在于使用的人。
I#AP;q-cN0