If you are familiar with Java, you should know that one type of Java cannot be inherited, that is, the final class. this type is useful, especially in the inheritance hierarchy of control classes in large projects. so that the number of child classes does not explode. this is also a good way to prevent the occurrence of a diamond hierarchy in the use of multi-inheritance class layers. there are many methods to implement a class that cannot be inherited.
The main idea is to make the subclass unable to construct the part of the parent class, so that the subclass cannot instantiate the entire subclass. this restricts subclass inheritance. therefore, the constructor of the parent class can be declared as private, but the parent class cannot be instantiated. I want to add a static help function for construction. although this is very simple. but this is indeed a solution.
However, if only this method can be solved, C ++ is too inflexible, and it is not worth writing a piece.ArticleCome out! Is there a way to solve the above problems?
We can take advantage of features that friends cannot inherit!
Assume that there is already a class cxx. this is a branch of a certain class level. Now we need to inherit a final subclass cparent from cxx, that is, cparent cannot be inherited. we can make full use of the features that friends cannot inherit, that is, to make cparent a member and a subclass of a class, cparent can be constructed, however, the cChild subclass of cparent cannot inherit the member feature, so it cannot be constructed. so we introduce a cfinalclassmixin.
We expect the functions of this class as follows:
- Any class inherited from it cannot be instantiated.
- At the same time, we do not want this class to be instantiated.
How to implement this class? Very easy! That is to say, we can implement a class that both constructor and destructor are private. At the same time, we can declare our cparent as friends in this class.CodeAs follows:
Class cfinalclassmixin {friend class cparent; private: cfinalclassmixin (){}~ Cfinalclassmixin (){}};> // Our cparent code should be as follows: Class cparent: publiccxxx {public: cparent (){}~ Cparent (){}};
It is a class extended from CXXX (note, it can still be inherited at this time). Now we need it not to be inherited. Just change the code
Class cparent: Public cfinalclassmixin, public CXXX {public: cparent () {}~~> Cparent (){}};
That's it. Now we can inherit a subclass from cparent.
Class cChild: Public cparent {};
Compile the code and try again:It does not work !!
Now let's look back at the reason for this operation, that is, the principle of this solution, that is, to allow the parent class to access the constructor of the Mixin class, but not the subclass.
Now let's look at our code and find that the parent class is a member of the cfinalclassmixin class and can access its constructor. because friends cannot inherit, cChild cannot access the constructor of cfinalclassmixin. so it should not be instantiated.
CChild cannot access the cfinalclassmixin constructor,But it does not have to call it!I think this is the cause of the problem. cChild uses cparent to construct cfinalclassmixin, so this member is of no use to him!
Now the problem has been found. It is easy to solve. As long as cChild needs to call the cfinalclassmixin constructor, how can this problem be achieved?
Do you still remember virtual inheritance? One feature of virtual inheritance is that the constructor of the virtual base class is constructed by the final subclass! Therefore, you can inherit cparent from cfinalclassmixin to cfinalclassmixin. The Code is as follows:
Class cparent: virtual public cfinalclassmixin, public CXXX {public: cparent () {} cparent (){}};
Try it now.
However, some people may have a lingering worry about inheritance! But we don't have to worry so much here! Why? Because our cfinalclassmixin class is pure! Pure! That is to say, it has no member variable at all! We don't have to worry about the biggest problem of multi-inheritance. The data redundancy produced by diamond inheritance and its ambiguity.
There is still a problem! That is, we cannot add the comments to a class to the cfinalclassmixin class every time! So much trouble! Although it is not a big problem, I think it is still necessary to solve it, because I fully trust C ++!
The solution is also very simple! The template is used! The specific description is omitted. You can see the code at a glance.
Below is my testProgramComplete code (cfinalclassmixin has been changed to a template)
// Finaltest. cpp: defines the entry point for the console application. // # include "stdafx. H" # include <iostream> using namespace STD;Template <class T>
Class cfinalclassmixin
{
Friend t;
PRIVATE:
Cfinalclassmixin (){}
~ Cfinalclassmixin (){}
};
Class CXXX
{
Public:
CXXX () {cout <"I am CXXX" <Endl ;}
~ CXXX (){}
};
Class cparent: virtual public cfinalclassmixin <cparent>, public CXXX
{
Public:
Cparent (){}
~ Cparent (){}
};
Class cChild: Public cparent {};
Int main (INT argc, char * argv [])
{
Cparent A; // can be constructed
// CChild B; // cannot be constructed
Return 0 ;}
Now you only need to add a cfinalclassmixin mixed class to the class you do not want to inherit as the parent class.
Through the restriction constructor, we have achieved the purpose of limiting inheritance. however, this is an exception, for example, it is a class of static functions. these classes do not need to be constructed. so we can't do it. however, in most cases, the number of classes that are all static functions implies that the design of the program may need to be considered.
In fact, this is only a small example of the Mixin class (mixed class. there are many other functions, such as uncopiale. I won't say much about it. I want to explain that you may dislike multi-inheritance. however, excessive negation is not worth the candle. whether or not to use multi-inheritance is still in the debate stage. I think whether a method is used properly depends on the person who uses it.
Lythm @ citiznet
2002 05 27
Author's blog:Http://blog.csdn.net/Lythm/Related Articles
Several Load Optimization Methods for 3D graphics rendering Channels |
Call DirectShow in VC to play video in full screen |
C ++ boost Python (generate an extension module) |
Python (inheritance) in C ++ boost) |
C ++ boost Python (a simple example) |
ajoo (-) |
about lostinet (I always think your ID is like "Lobster" ^_^) I think the actual work is enough. normally, anyone who wants to extend the class you write will come to consult you, or at least take a look at your documents? Therefore, although the document does not support enforce anything, I think there is not much problem in actual development. maybe this is also a reason why C ++ does not join "final" keyword. "You don't need it anymore. Why do you need to add it? " in Java," final ", in addition to prohibiting subclass from engineering, is actually a major support for Compiler optimization. If the compiler knows this class or the method is final, it can call this function without using a virtual function. C ++ seems to lack such a ban on the virtual function override: "I am the final implementation of this function. No one can override me. You can rest assured the compiler !" However, the use of "friend" seems difficult to play a similar role on the compiler. |
Ajoo (2002-06-23) |
I dont think typename, explicit are superfluous at all. Just as I don't think "final" keyword is superfluous. With "final", you don't have to play this kind of trick. That can just make tively make your code simpler. And, better than "Explicit", "final" will not potentially hurt any existing C ++ feature, semantics and optimizability. I guess the reason "final" is not in standard is because that the "standard" thing is quite political. I won't say anything added to the standard is necessarily the best approach (of course, it has to be good enough ). anything not added to the standard is necessarily bad or useless. about minimal keyword, your answer sounds so familiar. "Communism is the best one ". it really does not mean much. yes, we need to be conservative about adding keywords, but that does not necessarily disqualify adding a keyword, nor does it mean that the current collection of keywords is already perfect. Using debug/release trick shoshould also be cautious. Don't you see that the MI and virtual base class is changing the object's memory layout? If we allow such difference exist between release and debug, it's a sign of danger at least. Conditional compilation is one big reason why refactoring of C ++ code is so hard! And also, it is yet another step further toward Code complexity. |
Prototype (2002-06-22) |
> Prototype: Do you feel "Explicit", "typename" are also superfluous? No, I don't (but for different reasons). How about you? And why? > "Minimal keyword", don't know what that means. Who do you compare to say It's minimal? To itself? It is "minimal number of keywords". means to keep the number of keywords as less as possible. > Macro can remove overhead? Never know macro can be that great. Although I myself > Am a macro lover. Use the 'ndebug' trick. Thus no overhead in the release version. -- thought that was obvious.
|
Ajoo (2002-06-22) |
Keyword? What do you mean? prototype: Do you feel "Explicit", "typename" are also superfluous? (Probably not, because they are already in C ++) Thank God C ++ has a "friend" for you to do this trick. some people still complain about "friend" violating encapsulation! They don't know "friend" can play such an important role. You never know what a keyword can be used in C ++, right? Too submit possibilities. Don't think the C ++ author knows "friend" can be used for this. :) "Minimal keyword", don't know what that means. Who do you compare to say It's minimal? To itself? Clean trick? Well, we may have different view of clean code. Macro can remove overhead? Never know macro can be that great. Although I myself am a macro lover. |
|