Before discussing the impact of name hiding on public inheritance, let's take a look at what is name hiding and its impact on non-inheritance structures.
The name hiding rule in C ++ is simply understood as: when an object with a small scope (inner scope) a and a scope contains a (outer scope) when object B has the same name, B is invisible in the scope of. That is to say, B is completely blocked by.
double i = 3.1415;namespace XY{ bool i = false; void f() { int i = 926; cout << i << endl; }}
The output value of I in the above Code is 926, because the bool type I in global double type and namespace XY are all blocked by the local variables with the same name in function f. In this example, we can see that name hiding has nothing to do with the type of the variable to which the name belongs. Variables of different types will be blocked if their names are the same.
When name hiding occurs, the scope OPERATOR: can access outer variables in some cases. For example, when the outer variable you want to access is in the global scope, namespace, and class.
Double I = 3.1415; namespace XY {bool I = false; void F () {int I = 926; // output 0 cout <xy: I <Endl; // output 3.1415 cout <: I <Endl ;}}
In this example, xy: I explicitly tells the compiler that I will use the I in the namespace XY, while: I tells the compiler to use the I in the global space. However, there is no way to access outer scope variables in the following nested scopes.
Void F () {int I = 0; {double I = 3.1415; // The outer integer variable I cout cannot be accessed <I <Endl ;}}
In addition to variables, does a function have the problem of name hiding?
Void F (int I) {} void F (int I, Int J) {} namespace XY {void F () {F (1); // compilation error, global F (int I) has been blocked F (2, 3); // compilation error, global F (int I, Int J) has been blocked }}
From this example, we can see that as long as the function name is the same, all outer functions will be blocked, even if the types are different. This is exactly the same as what we observed on variables.
So, what is the impact of all these on inheritance? In an inheritance system, the scope of a derived class is embedded in the scope of the base class. The image is similar to the nested scope below.
Base {// The base class scope starts. derived {// The scope of the derived class starts.} // The scope of the derived class ends.} // The base class scope ends.
Let's take a look at this example.
Class base {public: Virtual void F (); Virtual void F (int I, Int J) ;}; class derived: public base {public: virtual void F () ;}; derived D; D. F (); D. F (1); // compilation error. The base class F (int I) has been blocked D. F (1, 2); // compilation error. The base class F (int I, Int J) has been blocked.
In this example, a base class has three overloaded virtual functions with the same name f. Override (redefine) is a function in the base class-F without parameters. We know that public inheritance shapes a "is-a" relationship, that is, any derived class object can be used as a base class object. This requires that the public interface Derived classes of all base classes must also have the same type; otherwise, the "is-a" relationship will be broken. In this example, because F without parameters is redefined in the derived class, the other two functions with the same name are blocked in the derived class. Therefore, the two interfaces cannot be accessed from outside.
This is not uncommon because function overloading and redefinition are common features of C ++. The solution is to extend the scope of functions with the same name of the base class to the derived class through the using statement. Of course, using must be used in the public of the derived class to ensure that these interfaces are still public.
class Base{public: virtual void f(); virtual void f(int i); virtual void f(int i, int j);};class Derived: public Base{public: using Base::f; virtual void f();};Derived d;d.f();d.f(1); //okd.f(1, 2); //ok
Summary:
- Avoid name conflicts whenever possible. Do not use variable names like I and j in the global space.
- If only one of the several overload functions of the base class is redefined, the using statement must be used to ensure that the public derived class inherits all interfaces of the base class with the same name.
- Another warning is that if you want to reload an existing function in the base class, make sure that the same interface exists in the derived class! Either redefinition or using. Well .. Adding Code to existing code is not that simple.