We can use a hidden base-class member by using the scope operator:
struct Derived : Base {
int get_base_mem() { return Base::mem; }
// ...
};
The scope operator overrides the normal lookup and directs the compiler to look for mem
starting in the scope of class Base
. If we ran the code above with this version of Derived
, the result of d.get_mem()
would be 0
.
Aside from overriding inherited virtual functions, a derived class usually should not reuse names defined in its base class.
Key Concept: Name Lookup and Inheritance
Understanding how function calls are resolved is crucial to understanding inheritance in C++. Given the call p->mem()
(or obj.mem()
), the following four steps happen:
• First determine the static type of p
(or obj
). Because we’re calling a member, that type must be a class type.
• Look for mem
in the class that corresponds to the static type of p
(or obj
). If mem
is not found, look in the direct base class and continue up the chain of classes until mem
is found or the last class is searched. If mem
is not found in the class or its enclosing base classes, then the call will not compile.
• Once mem
is found, do normal type checking (§6.1, p. 203) to see if this call is legal given the definition that was found.
• Assuming the call is legal, the compiler generates code, which varies depending on whether the call is virtual or not:
– If mem
is virtual and the call is made through a reference or pointer, then the compiler generates code to determine at run time which version to run based on the dynamic type of the object.
– Otherwise, if the function is nonvirtual, or if the call is on an object (not a reference or pointer), the compiler generates a normal function call.