Polymorphism 2
Polymorphism 2
andPolymorphismm
Final Remarks
Designing A Base Class with Inheritance and
Polymorphism
in mind
For a more complete discussion, see “Essential C++”, Stanley Lippman (section 5.4)
2
Name hiding
• If you inherit a class and provide a new definition for one of its
member functions, there are two possibilities.
1. The first is that you provide the exact signature and return type in the
derived class definition as in the base class definition.
This is called redefining for ordinary member functions and overriding
when the base class member function is a virtual function.
• But what happens if you change the member function argument list
or return type in the derived class? Here’s an example:
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
int f() const {
cout << "Base::f()\n";
return 1;
}
int f(string) const { return 1; }
void g() {}
};
class Derived1 : public Base {
public: int main() {
void g() const {}
}; string s("hello");
class Derived2 : public Base {
public:
Derived1 d1;
// Redefinition: int x = d1.f();
int f() const {
cout << "Derived2::f()\n"; d1.f(s);
}
return 2; Derived2 d2;
}; x = d2.f();
class Derived3 : public Base {
public: //! d2.f(s); // string version hidden
// Change return type: Derived3 d3;
void f() const { cout << "Derived3::f()\n"; }
}; //! x = d3.f(); // return int version
class Derived4 : public Base {
public: hidden
// Change argument list: Derived4 d4;
int f(int) const {
cout << "Derived4::f()\n"; //! x = d4.f(); // f() version hidden
return 4;
}
x = d4.f(1);
}; }
Name hiding
In Base you see an overloaded function f( ), and Derived1 doesn’t make any
changes to f( ) but it does redefine g( ).
In main( ), you can see that both overloaded versions of f( ) are available in
Derived1. However, Derived2 redefines one overloaded version of f( ) but not
the other, and the result is that the second overloaded form is unavailable.
In Derived3, changing the return type hides both the base class versions, and
Derived4 shows that changing the argument list also hides both the base class
versions.
In general,
we can say that anytime you redefine an overloaded function name from the
base class, all the other versions are automatically hidden in the new class.
Name hiding
If you change the interface of the base class by modifying the
signature and/or return type of a member function from the base
class, then you’re using the class in a different way than inheritance
is normally intended to support.
It doesn’t necessarily wrong, it’s just that the ultimate goal of
inheritance is to support polymorphism, and if you change the function
signature or return type then you are actually changing the interface of
the base class.
Functions that don’t automatically inherit
Not all functions are automatically inherited from the base class into the derived class. Constructors
and destructors deal with the creation and destruction of an object, and they can know what to do
with the aspects of the object only for their particular class, so all the constructors and destructors
in the hierarchy below them must be called. Thus, constructors and destructors don’t inherit and
must be created specially for each derived class.
In addition, the operator= doesn’t inherit because it performs a constructor-like activity. That is, just
because you know how to assign all the members of an object on the left-hand side of the =
from an object on the right-hand side doesn’t mean that the assignment will still have the same
meaning after inheritance.
Inheritance and static member functions
implementation. };
class Derived : public Base {
int j;
You can then allow controlled public:
Derived(int jj = 0) : j(jj) {}
access to inheritors of your void change(int x) { set(x); }
class Instrument {
public:
void play() const {}
};
// Wind objects are Instruments
// because they have the same interface:
class Wind : public Instrument {};
void tune(Instrument& i) {
// ...
i.play();
int main() {
Wind flute;
tune(flute); // Upcasting
}
Upcasting
This is why the compiler allows upcasting without any explicit casts or
other special notation.
Upcasting and the copy-
constructor
If you allow the compiler to synthesize a copy-constructor for a
derived class, it will automatically call the base-class copyconstructor,
and then the copy-constructors for all the member
objects (or perform a bitcopy on built-in types) so you’ll get the
right behavior:
Operator overloading & inheritance
Except for the assignment operator, operators are automatically
inherited into a derived class.