class Base
class Derived1
class Derived2
class Derived3
class Derived4
1: /** @file name_hiding1.cpp
2: Based on an example from Eckel, Thinking in C++, 2nd edition.
3: */
5: #include <iostream>
6: #include <string>
7: using namespace std;
9: class Base
10: {
11: public:
12: int f() const
13: {
14: cout << "\nExecuting Base::f() with int return type.";
15: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
16: return 1;
17: }
19: int f(string s) const
20: {
21: cout << "\nExecuting Base::f(string) with int return type.";
22: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
23: return 1;
24: }
26: void g()
27: {
28: cout << "\nExecuting Base::g() with void return type.";
29: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
30: }
31: };
34: class Derived1 : public Base
35: {
36: public:
37: void g() const
38: {
39: cout << "\nExecuting Derived1::g() with void return type.";
40: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
41: }
42: };
45: class Derived2 : public Base
46: {
47: public:
48: //Redefinition:
49: int f() const
50: {
51: cout << "\nExecuting Derived2::f() with int return type.";
52: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
53: return 2;
54: }
55: };
58: class Derived3 : public Base
59: {
60: public:
61: //Change return type:
62: void f() const
63: {
64: cout << "\nExecuting Derived3::f() with void return type.";
65: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
66: }
67: };
70: class Derived4 : public Base
71: {
72: public:
73: //Change argument list:
74: int f(int) const
75: {
76: cout << "\nExecuting Derived4::f(int) with int return type.";
77: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
78: return 4;
79: }
80: };
83: int main()
84: {
85: cout << "\nThis program illustrates the hiding of overloaded names "
86: "during inheritance.";
87: cout << "\nPress Enter to continue ... "; cin.ignore(80, '\n');
89: string s("Hello");
90: int n;
92: Derived1 d1;
93: n = d1.f();
94: d1.f(s);
96: Derived2 d2;
97: n = d2.f();
98: //d2.f(s); //1Compiler error: string version hidden
99: //error C2660: 'Derived2::f' : function does not take 1 arguments
101: Derived3 d3;
102: d3.f();
103: //n = d3.f(); //2Compiler error: return int version hidden
104: //error C2440: '=' : cannot convert from 'void' to 'int'
106: Derived4 d4;
107: //n = d4.f(); //3Compiler error: f() version hidden
108: //error C2660: 'Derived4::f' : function does not take 0 arguments
110: n = d4.f(1);
111: }
113: /*
114: Output
115: ------
117: This program illustrates the hiding of overloaded names during inheritance.
118: Press Enter to continue ...
120: Executing Base::f() with int return type.
121: Press Enter to continue ...
123: Executing Base::f(string) with int return type.
124: Press Enter to continue ...
126: Executing Derived2::f() with int return type.
127: Press Enter to continue ...
129: Executing Derived3::f() with void return type.
130: Press Enter to continue ...
132: Executing Derived4::f(int) with int return type.
133: Press Enter to continue ...
134: Press any key to continue . . .
135: */
137: /*
138: Notes:
139: If you inherit a class and provide a new definition for one of its
140: member functions, there are two possibilities:
141: - The new function has exactly the same signature and return type
142: in the derived class as in the base class. This is called
143: -- "redefining" for ordinary member functions
144: -- "overriding" for virtual base class member functions
146: What exactly is the situation if you change the member function
147: argument list or return type? The above example illustrates ...
149: In Base you see an overloaded function f().
151: Derived1 makes no changes to f() but does redefine g().
152: In main we see that both overloaded versions of f() are available
153: in Derived1.
155: Derived2 redefines one overloaded version of f() but not the other.
156: The result is that the second overloaded form is not available.
158: Derived3 changes the return type of f() and hides *both* of the
159: Base class versions of f().
161: Derived4 changes the parameter list of f() and also hides both of
162: the Base class versions of f().
164: So, in general, whenever you redefine an overloaded function name
165: from a base class in a derived class, all the other versions of
166: that function are hidden in the new class.
168: But also note carefully the following:
169: If you change the interface of the base class by modifying the signature
170: and/or the return type of a member function from a base class, then you
171: are using the class in a different way than inheritance in normally
172: intended to support. This may or may not be "wrong", it's just that
173: the ultimate goal of inheritance is to support *polymorphism*, and if
174: you change the function signature you are actually changing the interface
175: of the base class.
177: If that's what you actually intended, then you are using inheritance
178: simply to reuse code, and not to maintain the common interface of the
179: base class (an essential aspect of polymorphism). In general, when you
180: use inheritance this way, it means you are taking a general purpose
181: class and specializing it for a particular need, which may mean that
182: what you really need to be using is composition (making an object of
183: the new class a data member of the original class), rather than
184: inheritance.
185: */