"Yoga mountains and nights"-exploring the root cause of inheritance (1)

Source: Internet
Author: User

Abstract: inheritance is a very important feature of C ++ and one of the three features of OO. I hope to make a simple discussion on it to eliminate some confusions.

What is inheritance?
Inheritance is a method of organizing related classes and distributing common data and operation behaviors. It is also important to note that the inheritance relationship is strongly coupled.

What is the purpose of inheritance?
When it comes to the purpose of inheritance, people always think of code reuse. Actually, code reuse is only a side effect of inheritance. The main purpose of inheritance is to express an external meaningful relationship, this relationship describes the behavioral relationships between two entities in the problem domain. In other words, inheritance is generated because of the reality of the problem domain, not because of the technical purpose of the solution domain.

What are the obstacles to inheritance?
The use of inheritance is not as simple as we think. When deciding on inheritance, there are many language features that may constitute some obstacles.
1. Non-virtual member functions exist.
If we confirm that a member function in a base class is non-virtual, it means that this function should not be redefined in the derived class. If you redefine it, the result is probably not what you expected, for example:
Class
{Public: void F () {cout <"A: F" <Endl ;}};
Class B: public
{Public: void F () {cout <"B: F" <Endl ;}};
A * pA = new B;
Pa-> F ();
Delete Pa;
Here, we may expect that Pa-> F () will output B: F, but it is actually a: f. Of course, if we declare it as virtual, there will be no problem, the key is how can we clearly determine that function should be declared as virtual? How can we make the base class fully predict the various requirements of the subclass? Undoubtedly, this is a challenge! It may be a simple solution to declare all the base class member functions as virtual, but this will greatly reduce the execution efficiency of the program. For C ++, which focuses on efficiency, this is a betrayal of it. c ++ wants us to declare the functions that need to be redefined as virtual.
2. Over-Protection of base class members
Encapsulation is a good feature, but it is difficult to grasp the encapsulation degree. For example:
Class
{PRIVATE: Class P {...};};
Class B: Public A: P {...};
Experienced programmers will immediately realize that this is an error: cannot get a: P, because its permission is private! Of course, you only need to change private to protected, but the key is how to predict the class to be inherited by the base class? This is also a challenge, just like an obstacle. Naive programmers may think that it is okay to declare all the members of the base class as public/protected, but after the release of our class, members of public/protected cannot be changed any more. Otherwise, the customer's code will be interrupted, which requires us to encapsulate implementation details as private as much as possible, only declare the Members whose subclass needs to be changed as public/protected permissions (virtual functions can be declared as private, which is an exception), but the requirements for the designers of the base class are so high, it is also very difficult.
3. Lack of modular design in the base class
Modularization will make the program more concise and effective, but it is not easy for the base class to implement effective modularization. For example, we have a binary search tree bstree, which is defined as follows:
Template <class T>
Class bstree
{
PRIVATE:
Class Node
{
Public:
T;
Node * left;
Node * right;
Node (const T & _ T): T (_ t ){}
...
};
Node * root;
...
Public:
Void insert (const T & T );
...
Protected:
Virtual void doinsert (const T & T, node * & N );
...
};
Template <class T>
Void bstree <t >:: doinsert (const T & T, node * & N)
{
If (n = 0) n = new node (t );
Else
{
If (T <n-> T) doinsert (t, n-> left );
Else doinsert (t, n-> right );
}
}
Now, we need to define a red/black tree as follows:
Template <class T>
Class rbtree: Public bstree <t>
{
Protected:
Class node: Public bstree <t>: Node
{
Public:
Bool is_red;
Node (const T & T );
};
Void doinsert (const T & T, bstree <t>: node * & N );
Virtual void rebalance (node * n );
...
};
Template <class T>
Void bstree <t >:: doinsert (const T & T, node * & N)
{
If (n = 0)
{
Node M = new node (t );
N = m;
Rebalance (m );
}
Else
{
If (T <n-> T) doinsert (t, n-> left );
Else doinsert (t, n-> right );
}
}
We found that bstree: doinsert and rbtree: doinsert code are roughly the same, so there is a copy code operation, we know that code replication is boring, error-prone, code bloated, and difficult to maintain... therefore, a good base class should make the derived class copy the code as little as possible, and it is best not to copy. Let's look at our base class: Many Binary Search Trees need to create different nodes and rebalance operations. Well, we should modify the base class bstree as follows:
Template <class T>
Class bstree
{
Protected:
Virtual node * new_node (const T & T)
{Return new node (t );}
Virtual void rebalance (node * n ){}
...
};
The doinsert changes are as follows:
Template <class T>
Void bstree <t >:: doinsert (const T & T, node * & N)
{
If (n = 0)
{
N = new_node (t );
Rebalance (N );
}
Else
{
If (T <n-> T) doinsert (t, n-> left );
Else doinsert (t, n-> right );
}
}
In this case, the rbtree definition of the derived class is changed:
Template <class T>
Class rbtree: Public bstree <t>
{
Protected:
Node * new_node (const T & T)
{Return new node (t );}
Void rebalance (bstree <t>: node * n)
{...}
...
};
In this way, programmers do not need to copy the code. We found that if the customer of the derived class never copies the code, it is necessary to separate the code that needs to be changed from the derived class to form a separate module function (virtual ), however, when we do not have enough information about the derived classes, this is impossible. Even if possible, the difficulty is quite high. At the same time, a large number of virtual functions will reduce the execution efficiency of the program.
4. over-use of the friend keyword
The root cause of this problem is the non-inheritance of the relationship between friends and members. We still use the above example, but make the following changes:
Template <class T> class bstree;
Template <class T>
Class bsnode
{
Protected:
T;
Bsnode (const T & T );
Friend class bstree <t>;
};
Template <class T>
Class bstree
{
... No nested node class
};
Here, because the implementation of bsnode is part of the Implementation Details of bstree, and to prevent bsnode Derived classes from accidentally accessing the members of bsnode, we declare all its members as protected, bstree is also called its member. However, because rbtree needs to access bsnode members and the non-inheritance of friends, there are usually two ways to solve this problem:
1. Declare the bsnode member as public, but it makes no sense to use friend.
2. Add an access function in the rbnode class, but it is much more troublesome than using friend.
There are also some other choices that are also a headache. For example, there are too many member variables in the base class and the selection of inherited attributes.

Unfinished (To be continued ...)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.