Source of name_hiding2.cpp


  1: /** @file name_hiding2.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:     virtual 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:     virtual void f(string s) const
 20:     {
 21:         cout << "\nExecuting Base::f(string) with void return type.";
 22:         cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 23:     }

 25:     virtual void g() const
 26:     {
 27:         cout << "\nExecuting Base::g() with void return type.";
 28:         cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 29:     }
 30: };


 33: class Derived1 : public Base
 34: {
 35: public:
 36:     void g() const
 37:     {
 38:         cout << "\nExecuting Derived1::g() with void return type.";
 39:         cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 40:     }
 41: };


 44: class Derived2 : public Base
 45: {
 46: public:
 47:     //Overriding a virtual function:
 48:     int f() const
 49:     {
 50:         cout << "\nExecuting Derived2::f() with int return type.";
 51:         cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 52:         return 2;
 53:     }
 54: };


 57: class Derived3 : public Base
 58: {
 59: public:
 60:     //Cannot change return type:
 61:     //void f() const
 62:     //{
 63:     //    cout << "\nExecuting Derived3::f() with void return type.";
 64:     //    cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 65:     //}
 66: };


 69: class Derived4 : public Base
 70: {
 71: public:
 72:     //Change argument list:
 73:     int f(int) const
 74:     {
 75:         cout << "\nExecuting Derived4::f(int) with int return type.";
 76:         cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');
 77:         return 4;
 78:     }
 79: };


 82: int main()
 83: {
 84:     cout << "\nThis program illustrates how virtual functions restrict "
 85:         "their overloading\nin derived classes, and shows how this "
 86:         "prevents the breaking of the\n\"polymorphic contract\" that "
 87:         "virtual functions provide.";
 88:     cout << "\nPress Enter to continue ... ";  cin.ignore(80, '\n');

 90:     string s("hello");
 91:     int n;

 93:     Derived1 d1;
 94:     n = d1.f();
 95:     d1.f(s);

 97:     Derived2 d2;
 98:     n = d2.f();
 99:     //d2.f(s); //1string version hidden
100:     //error C2660: 'Derived2::f' : function does not take 1 arguments


103:     Derived4 d4;
104:     n = d4.f(1);
105:     //n = d4.f();  //2f() version hidden
106:     //error C2660: 'Derived4::f' : function does not take 0 arguments

108:     //d4.f(s);     //3string version hidden
109:     //error C2664: 'Derived4::f' :
110:     //cannot convert parameter 1 from 'std::string' to 'int'

112:     Base& br = d4; //Upcast
113:     //br.f(1);     //4Derived version unavailable
114:     //error C2664: 'void Base::f(std::string) const' :
115:     //cannot convert parameter 1 from 'int' to 'std::string'

117:     br.f();        //Base version available
118:     br.f(s);       //Base version available
119: }

121: /*
122: Output
123: ------

125: This program illustrates how virtual functions restrict their overloading
126: in derived classes, and shows how this prevents the breaking of the
127: "polymorphic contract" that virtual functions provide.
128: Press Enter to continue ...

130: Executing Base::f() with int return type.
131: Press Enter to continue ...

133: Executing Base::f(string) with void return type.
134: Press Enter to continue ...

136: Executing Derived2::f() with int return type.
137: Press Enter to continue ...

139: Executing Derived4::f(int) with int return type.
140: Press Enter to continue ...

142: Executing Base::f() with int return type.
143: Press Enter to continue ...

145: Executing Base::f(string) with void return type.
146: Press Enter to continue ...
147: Press any key to continue . . .
148: */

150: /*
151: Notes:
152: In Derived3, the compiler will not let you change the return type of
153: the overriden function f(). It would be allowed if f() were not virtual.
154: This is an important restriction because the compiler must guarantee
155: that you can polymorphically call the function through the base class,
156: and if the base class is expecting an int to be returned from f() then
157: the derived class version of f() must keep that part of the contract or
158: else things will break.

160: As before, if you override one of the overloaded member functions in the
161: base class the other overloaded versions become hidden in the derived
162: class. In main(), the code that tests Derived4 shows that this happens
163: even if the new version of f() isn't actually overriding an existing
164: virtual function interface-both of the base-class versions of f() are
165: hidden by f(int). However, if you upcast d4 to Base, then only the
166: base-class versions are available (because that's what the base-class
167: contract promises) and the derived-class version is not available
168: (because it isn't specified in the base class).
169: */