Polymorphic Usage Of Objects¶
What Larger Systems Want¶
What we have
Automatic conversion from
Derived
toBase
virtual
⟶ callDerived::method()
throughBase*
What we want
Have multiple objects of different concrete types (say,
Derived1
,Derived2
) in a systemAccess them through their base types
⟶ interfaces (but there are gotchas - see C++ “Interfaces”)
⟶ polymorphic usage of objects
Why do we want this?
System must not depend on one concrete type out of many
#include <iostream>
class Base
{
public:
virtual void method() const
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived1 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived1::method()" << std::endl;
}
};
class Derived2 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived2::method()" << std::endl;
}
};
int main()
{
Base* thermometers[2];
Derived1 d1;
Derived2 d2;
thermometers[0] = &d1;
thermometers[1] = &d2;
for (int i=0; i<2; i++)
thermometers[i]->method();
return 0;
}
$ ./inher-oo-polymorphic
Derived1::method()
Derived2::method()
Pitfall ⟶ Pure Virtual Methods¶
Problem
Base::method()
is there (has an implementation that can be invoked)Used when a derived class does not override it
⟶ Countless source of errors; e.g.
Developer goes out for coffee before implementing
Derived3::method()
Comes back, not knowing where she left off
Everything compiles ⟶ false expectation of correctness
Base::method()
used ⟶ Bug!!
#include <iostream>
class Base
{
public:
virtual void method() const
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived1 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived1::method()" << std::endl;
}
};
class Derived2 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived2::method()" << std::endl;
}
};
class Derived3 : public Base // <--- BUG: not implementing method()
{
};
int main()
{
Base* thermometers[3];
Derived1 d1;
Derived2 d2;
Derived3 d3; // <--- BUG: instantiating incomplete type
thermometers[0] = &d1;
thermometers[1] = &d2;
thermometers[2] = &d3; // <--- BUG: using incomplete type
for (int i=0; i<3; i++)
thermometers[i]->method();
return 0;
}
$ ./inher-oo-polymorphic-not-pure
Derived1::method()
Derived2::method()
Base::method() # <--- BUG!
Pure Virtual Method¶
Solution
Pure virtual method
virtual Base::method() const = 0;
#include <iostream>
class Base
{
public:
virtual void method() const = 0; // <--- purposely left unimplemented!!
};
class Derived1 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived1::method()" << std::endl;
}
};
class Derived2 : public Base
{
public:
virtual void method() const
{
std::cout << "Derived2::method()" << std::endl;
}
};
class Derived3 : public Base // <--- ERROR: not implementing method()
{
};
int main()
{
Base* thermometers[3];
Derived1 d1;
Derived2 d2;
Derived3 d3;
thermometers[0] = &d1;
thermometers[1] = &d2;
thermometers[2] = &d3;
for (int i=0; i<3; i++)
thermometers[i]->method();
return 0;
}
inher-oo-polymorphic-pure.cpp:39:14: error: cannot declare variable ‘d3’ to be of abstract type ‘Derived3’
39 | Derived3 d3;
| ^~
inher-oo-polymorphic-pure.cpp:28:7: note: because the following virtual functions are pure within ‘Derived3’:
28 | class Derived3 : public Base
| ^~~~~~~~
inher-oo-polymorphic-pure.cpp:7:18: note: ‘virtual void Base::method() const’
7 | virtual void method() const = 0;
| ^~~~~~