作者:CUJ
今天看到《軟體研發5》有一篇譯自CUJ的文章“使類不可繼承”,方法很好,但有幾個毛病:
1. 正如譯者說的,還是有辦法進行繼承,雖然方法有點變態
2. 最主要的毛病卻是,這種辦法會造成運行時的開銷。因為至少會增加VTABLE指針。
所以,針對以上兩個問題,作了改動,如下:
1 #ifdef _DEBUG
2
3 namespace internalSealed
4 {
5 template<typename T>
6 class Class_Is_Sealed
7 {
8 protected:
9 Class_Is_Sealed(){};
10 };
11 }
12
13 template<typename T>
14 class Sealed: private virtual internalSealed::Class_Is_Sealed<T>
15 {
16 friend typename T;
17 };
18
19 #else
20
21 template<typename T>
22 class Sealed
23 {
24 };
25
26 #endif
2
3 namespace internalSealed
4 {
5 template<typename T>
6 class Class_Is_Sealed
7 {
8 protected:
9 Class_Is_Sealed(){};
10 };
11 }
12
13 template<typename T>
14 class Sealed: private virtual internalSealed::Class_Is_Sealed<T>
15 {
16 friend typename T;
17 };
18
19 #else
20
21 template<typename T>
22 class Sealed
23 {
24 };
25
26 #endif
這樣子,在Debug方式下,只要一個類從Sealed<T>繼承,就不可再被繼承了。
同時,在Release方式下,因為不再檢查是否可以被繼承,因而不產生開銷(空類會被編譯器優化掉)。
使用例子:
1 #include "Sealed.h"
2
3 class test: Sealed<test>
4 {
5 public:
6 int print()
7 {
8 return 1;
9 }
10 };
11
12 class ttt: public test //, Sealed<test>, Sealed<ttt>
13 {
14 public:
15 int print()
16 {
17 return 2;
18 }
19 };
20
21 int main(int argc, char* argv[])
22 {
23 test t;
24 printf("%d\n", t.print());
25
26 ttt t1;
27 printf("%d\n", t1.print());
28 return 0;
29 }
2
3 class test: Sealed<test>
4 {
5 public:
6 int print()
7 {
8 return 1;
9 }
10 };
11
12 class ttt: public test //, Sealed<test>, Sealed<ttt>
13 {
14 public:
15 int print()
16 {
17 return 2;
18 }
19 };
20
21 int main(int argc, char* argv[])
22 {
23 test t;
24 printf("%d\n", t.print());
25
26 ttt t1;
27 printf("%d\n", t1.print());
28 return 0;
29 }