Trying to get my head round using polymorphism in C++. Below are two base abstract classes, Duck and FlyingBehavior, and a series of inherited classes (this is based on the first chapter from Head First Design Patterns).
// Define an abstract fly behaviour class
class FlyBehavior {
public:
virtual void fly() { cout << "No Flying Set!" << endl; }
};
class FlySwoop : public FlyBehavior {
public:
void fly() { cout << "Swoop Flying!" << endl; }
};
class CantFly : public FlyBehavior {
public:
void fly() { cout << "Can't Fly!" << endl; }
};
// Define an abstract Duck class
class Duck {
CantFly nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};
// Define a new Mallard Duck class
class MallardDuck : public Duck {
FlySwoop fb;
public:
MallardDuck(){ setFlyBehavior(&fb); }
};
// Define a new Rubber Duck class
class RubberDuck : public Duck {
CantFly fb;
public:
RubberDuck(){ setFlyBehavior(&fb); }
};
// Define a new Toilet Duck Class
class ToiletDuck : public Duck {};
int main(void) {
Duck *p;
MallardDuck mallardDuck;
RubberDuck rubberDuck;
ToiletDuck toiletDuck;
p = &mallardDuck;
p->goFly();
p = &rubberDuck;
p->goFly();
p = &toiletDuck;
p->goFly();
}
Using the above code I get the following output
Swoop Flying!
Can't Fly!
Can't Fly!
when I was expecting
Swoop Flying!
Can't Fly!
No Flying Set!
Am I approaching this example the right way (use to doing it in Java)? Can't help but feel that I'm missing something fundamental. I'm trying to understand how you pull out a behaviour from a class, put it into another class, and then use polymorphism to delegate to the right behavior. Is there a better way to approach the above?
Hmmm, perhaps this where you use multiple inheritance instead?
If you change
class Duck {
CantFly nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};
to
class Duck {
FlyBehavior nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};
your code will produce desired output.
In the current version of the code ToiletDuck compiler-generated default constructor calls a default constructor of the Duck class which sets nf to point to an instance of theCantFly class. Of course, it prints Can't fly.
First, your code has no abstract base classes. An abstract base class is one that has pure virtual member functions (such as virtual fly() const=0). FlyBehavior is a polymorphic class, but not abstract, since its virtual function is not pure virtual. Duck is not even a polymorphic class (has no virtual member methods).
Second, any polymorphic classes should have a virtual destructor, so that any object of derived type can be deleted from a pointer to the polymorphic base.
Next, the derived ducks have more data members than actually used. MallardDuck, for example, has a CantFly, a FlySwoop and a FlyBehaviour*. This can be avoided by allocating the actual FlyBehaviour on the heap and managing it through a smart pointer. (This may not be an issue with this simple example, but as soon as those objects get large it will become a problem.)
Finally, the member function setFlyBehavior() is exposed to the public, allowing the user to change the FlyBehavior -- do you really want that?
A possible design is as follows
struct FlyBehavior // polymorphic class
{
virtual void fly() const { cout << "No Flying Set!" << endl; }
virtual~FlyBehavior() {}
};
struct FlySwoop : FlyBehavior
{
void fly() const { cout << "Swoop Flying!" << endl; }
};
struct CantFly : FlyBehavior
{
void fly() const { cout << "Can't Fly!" << endl; }
};
class Duck // non-polymorphic, but using polymorphism through member
{
std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:
Duck() : flyBehavior(new FlyBehavior) {} // note: not CantFly as in your code
Duck(Duck&&) = default; // allow move (but no copy)
Duck&operator=(Duck&&) = default;
void goFly() const { flyBehavior->fly(); }
};
struct MallardDuck : Duck
{
MallardDuck() : Duck(new FlySwoop) {}
};
struct RubberDuck : Duck
{
RubberDuck() : Duck(new CantFly) {}
};
Often it is preferrable for FlyBehavior to be abstract. In this case, Duck can be implemented with only a protected constructor (apart from move & copy):
struct FlyBehavior // polymorphic class
{
virtual void fly() const=0 ; // pure virtual
virtual~FlyBehavior() {}
};
class Duck // non-polymorphic, but using polymorphism through member
{
std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:
Duck() = delete; // no default constructor
Duck(Duck&&) = default; // allow move (but no copy)
Duck&operator=(Duck&&) = default;
void goFly() const { flyBehavior->fly(); }
};
and the remaining code as above. The difference is that you cannot create a Duck object, but only one of the derived Duck types. Which of these two designs is most suitable depends on the application.
Related
For example, I have 2 classes (in reality, it's more, that's why I'm asking this question) with the same methods:
class class1{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
class class2{
public:
void init(){
//something
}
void dostuff(){
//something
}
//
};
And now a third one in which I want to deal with the two classes in the same manner:
class upclass{
public:
upclass(class12* argclass){
myclass=argclass;
myclass->init();
}
void domorestuff(){
myclass->dostuff();
}
private:
class12* myclass; //pointer to class 1 OR class 2
};
My question is now, do I need multiple constructors and multiple declarations to make it work or is there a way around it? Is it even possible to make "class12" a spacekeeper for these types without preprocessor-directives?
I am sorry to say, this is a wide field and there are really many many possible solution.
But I guess that we are talking about object- oriented programming, derivation and plymorphic functions. What you describe, will be typically solved with a class hierachy.
You have one base class with virtual (polymorphic) functions.
Then you derive other classes from this base class and override the virtual functions from the base class.
In a 3rd step, you create some instances of the derived classes dynamically, during runtime and you store the newly created classes (their address) in a pointer to the base class.
Later, you can call any of the virtual overriden function through the base class pointer. And mechanism behind the scenes will call the correct function for you.
Additionally. You defined some function init. Such a function name suggests the usage of a class-constructor. This will be called automatically in the correct sequence. First the base class constructor and then the derived class constructor.
Please see the below example:
#include <iostream>
#include <string>
class Base {
std::string baseName{};
public:
Base() { // Do initialization stuff
baseName = "Base";
std::cout << "\nConstructor Base\n";
}
virtual void doStuff() { // virtual function
std::cout << baseName << '\n';
}
};
class Derived1 : public Base {
std::string derivedName{};
public:
Derived1() : Base() { // Do initialization stuff
derivedName = "Derived1";
std::cout << "Constructor Derived1\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
class Derived2 : public Base {
std::string derivedName{};
public:
Derived2() : Base() { // Do initialization stuff
derivedName = "Derived2";
std::cout << "Constructor Derived2\n\n";
}
void doStuff() override { // Override virtaul function
std::cout << derivedName << '\n';
}
};
int main() {
Base* base = new Base();
Base* derived1 = new Derived1(); // Store in base class pointer
Base* derived2 = new Derived2(); // Store in base class pointer
base->doStuff();
derived1->doStuff(); // Magic of polymorphism
derived2->doStuff(); // Magic of polymorphism
}
The Base class pointer will accept all classes derived from Base.
Please note. In reality you ould not use raw pointers and also to the constructor differently. This is just fotr demo.
But, you need to read several books about it to get the complete understanding.
You can explicitly write "store one of these" via std::variant and obtain the actual type (when needed) through std::visit:
#include <variant>
using class12 = std::variant<class1*, class2*>;
class upclass {
public:
upclass(class12 argclass): myclass{argclass} {
visit([](auto classn) { classn->init(); }, myclass);
}
void domorestuff() {
visit([](auto classn) { classn->dostuff(); }, myclass);
}
private:
class12 myclass;
};
If those visits get too repetitive, you might consider writing a pretty API to hide them:
class prettyclass12: public std::variant<class1*, class2*> {
private: // both g++ and clang want variant_size<>, a quick hack:
auto& upcast() { return static_cast<std::variant<class1*, class2*>&>(*this); }
public:
using std::variant<class1*, class2*>::variant;
void init() { visit([](auto classn) { classn->init(); }, upcast()); }
void dostuff() { visit([](auto classn) { classn->dostuff(); }, upcast()); }
};
class prettyupclass {
public:
prettyupclass(prettyclass12 argclass): myclass{argclass} { myclass.init(); }
void domorestuff() { myclass.dostuff(); }
private:
prettyclass12 myclass;
};
Apologies for this quite abstract title.
More clearly:
I have two classes Controler and Interface (hardware sense, unrelated to design pattern)
Both are abstract with some pure virtual methods and hence intended to be subclassed
I need each Controler created to be associated with an Interface object
Each Controler subclass only work with a subset of Interface subclasses (ControlerA + InterfaceA or ControlerB + InterfaceB but not ControlerA + InterfaceB)
Each Interface subclass has its own methods not inherited (this is why only one kind of Controler can use it)
The Controler base class need to call some method of the base class Interface
I try to pass an Interface objet to the Controler constructor, hence in my class definition the Interface attribute represents the abstract base class. But if my Controler subclass A need to call a specific method of the Interface A, an compilation error is raised as the Interface base class doesn't own this method.
The only workaround I found was to call dynamic_cast, but it obviously seems wrong.
Here are my Interface classes:
class Interface {
public:
Interface() {};
virtual void method() = 0;
};
class InterfaceA : public Interface {
public:
InterfaceA() : Interface() {};
void method() override { cout << "A overriding" << endl; }
void onlyA() { cout << "A only" << endl; }
};
class InterfaceB : public Interface {
public:
InterfaceB() : Interface() {};
void method() override { cout << "B overriding" << endl; }
void onlyB() { cout << "B only" << endl; }
};
Here are my Controler classes:
class Controler {
public:
Controler(Interface* i) : m_interface(i) {};
virtual void uniqueMethod() = 0;
void commonMethod() { m_interface->method(); }
Interface* m_interface;
};
class ControlerA : public Controler {
public:
ControlerA(InterfaceA* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceA *>(m_interface)->onlyA();}
};
class ControlerB : public Controler {
public:
ControlerB(InterfaceB* i) : Controler(i) {};
void uniqueMethod() override {dynamic_cast<InterfaceB *>(m_interface)->onlyB();}
};
And here is how I plan to use them:
auto ia = new InterfaceA();
auto ca = ControlerA(ia);
ca.commonMethod(); // Method defined in the base class
ca.uniqueMethod(); // Method defined in InterfaceA only
You can try it on Repl.it.
Is there any design pattern to solve this issue?
There is a problem indeed. There exists an invariant between the dynamic type of m_interface and the dynamic type of the object that implement Controler. But this invariant cannot be maintained by the Controler class. So the m_interface member is not a the right place.
The consequence is that you need to check at runtime that this member has the right type by using the dynamic_cast each time you call uniqueMethod. If the invariant is broken, the code will have UB because it would dereference a null pointer.
So this is not really a design pattern issue, but more fundamentally an object oriented programming recommendation: classes must ensure invariants.
class Controler {
public:
virtual void uniqueMethod() = 0;
virtual void commonMethod() = 0;
};
class ControlerA : public Controler {
public:
ControlerA(InterfaceA* i):m_interface{i} {
assert(dynamic_cast<InterfaceA*>(i)!=nullptr);
};
void uniqueMethod() override { m_interface->onlyA();}
void commonMethod() override { m_interface->method(); }
private: InterfaceA* m_interface;
};
class ControlerB : public Controler {
public:
ControlerB(InterfaceB* i):m_interface{i} {
assert(dynamic_cast<InterfaceB*>(i)!=nullptr);
};
void uniqueMethod() override { m_interface->onlyB();}
void commonMethod() override { m_interface->method(); }
private: InterfaceB* m_interface;
};
So now, it looks that we have a regular pattern, so this is where we can think about a more generic design:
template<class Inter,void(Inter::* OnlyFunc)()>
class ControlerImpl : public Controler {
public:
ControlerImpl(Inter* i):m_interface{i} {
assert(dynamic_cast<Inter*>(i)!=nullptr);
};
void uniqueMethod() override { (m_interface->*OnlyFunc)();}
void commonMethod() override { m_interface->method(); }
private: Inter* m_interface;
};
using ControlerA = ControlerImpl<InterfaceA,&InterfaceA::onlyA>;
using ControlerB = ControlerImpl<InterfaceB,&InterfaceB::onlyB>;
I am expecting "My Game" to print out but I am getting "Base"
This only happens when using methods internally inside the class.
#include <iostream>
namespace Monster { class App {
public:
App(){}
~App(){}
void run(){
this->speak();
}
void speak(){
std::cout << "Base" << "\n";
};
};}; // class / namespace
class MyGame : public Monster::App {
public:
MyGame(){}
~MyGame(){}
void speak(){
std::cout << "My Game" << "\n";
};
};
int main(){
MyGame *child = new MyGame;
child->run();
return 0;
}
In C++ you need to specifically declare a function to be virtual:
class BaseClass {
virtual void speak () {
...
}
};
In C++ a method can only be overridden if it was marked virtual. You can think of virtual as a synonym for "overridable".
The virtual keyword has to appear in the base class. It may also appear optionally in the subclasses at the point of override, but it does not have to.
If you are using a compiler that supports C++11 (and you should if you are learning C++), I recommend that you always use the new override keyword when you mean to override:
class Base {
public:
virtual void speak() {
std::cout << "Base";
}
};
class Derived : public Base {
public:
void speak() override { // <---
std::cout << "Derived";
}
};
If the method isn't actually an override, the compiler will tell you so by giving an error.
It is not always obvious on the first read whether a method is an override. For example the following is correct thanks to return type covariance:
class A {};
class B : public A {};
class Base {
public:
virtual A* foo() {
return nullptr;
}
};
class Derived : public Base {
public:
B* foo() override {
return nullptr;
}
};
This might not be useful very often, but override makes it clear in case someone has to read it.
Also, if you have at least one virtual method in your class, also make its destructor virtual. This will assure that all the destructors will run when needed and things get cleaned up properly:
class App {
public:
App() {}
virtual ~App() {} // <---
void run() {
this->speak();
}
virtual void speak() {
std::cout << "Base\n";
};
};
I am expecting "My Game" to print out but I am getting "Base"
This only happens when using methods internally inside the class.
#include <iostream>
namespace Monster { class App {
public:
App(){}
~App(){}
void run(){
this->speak();
}
void speak(){
std::cout << "Base" << "\n";
};
};}; // class / namespace
class MyGame : public Monster::App {
public:
MyGame(){}
~MyGame(){}
void speak(){
std::cout << "My Game" << "\n";
};
};
int main(){
MyGame *child = new MyGame;
child->run();
return 0;
}
In C++ you need to specifically declare a function to be virtual:
class BaseClass {
virtual void speak () {
...
}
};
In C++ a method can only be overridden if it was marked virtual. You can think of virtual as a synonym for "overridable".
The virtual keyword has to appear in the base class. It may also appear optionally in the subclasses at the point of override, but it does not have to.
If you are using a compiler that supports C++11 (and you should if you are learning C++), I recommend that you always use the new override keyword when you mean to override:
class Base {
public:
virtual void speak() {
std::cout << "Base";
}
};
class Derived : public Base {
public:
void speak() override { // <---
std::cout << "Derived";
}
};
If the method isn't actually an override, the compiler will tell you so by giving an error.
It is not always obvious on the first read whether a method is an override. For example the following is correct thanks to return type covariance:
class A {};
class B : public A {};
class Base {
public:
virtual A* foo() {
return nullptr;
}
};
class Derived : public Base {
public:
B* foo() override {
return nullptr;
}
};
This might not be useful very often, but override makes it clear in case someone has to read it.
Also, if you have at least one virtual method in your class, also make its destructor virtual. This will assure that all the destructors will run when needed and things get cleaned up properly:
class App {
public:
App() {}
virtual ~App() {} // <---
void run() {
this->speak();
}
virtual void speak() {
std::cout << "Base\n";
};
};
My code structure is like below where multiple classes implement Interface. In Example class I store a pointer to the Interface and new() it in the constructor appropriately (depending on constructor parameters not shown here). I'm looking for ways to avoid using new() in this scenario but haven't got a solution yet. What's the best practice for something like this?
class Interface
{
virtual void Foo() = 0;
};
class A : public Interface
{
void Foo() { ... }
};
class B : public Interface
{
void Foo() { ... }
};
class Example
{
private:
Interface* m_bar;
public:
Example()
{
m_bar = new A(); // deleted in destructor
}
};
There are two ways this is typically done, each with their own merits.
If A is truely defined at compile time, than a typical way to handle this is to simply use a template type:
template <typename T>
class TemplateExample
{
T m_bar;
public:
TemplateExample() : m_bar() {};
}
This has some downsides. TemplateExample<A> becomes unrelated to TemplateExample<B>, the error messages when T doesn't follow the correct interface are pretty obtuse, ect. The upside is this may use duck typing rather than interface typing, and m_bar is a concrete instance.
The other (arguable more common) way is to do the following
class UniquePtrExample
{
std::unique_ptr<Interface> m_bar;
public:
UniquePtrExample() : m_bar(new A()){}
};
This has the benefit of being able to be run time configuratble if you follow a cloable pattern:
class Interface
{
public:
virtual void Foo() = 0;
virtual Interface* clone() const = 0;
};
template <typename T>
class CloneHelper : public Interface
{
public:
virtual Interface* clone() const { return new T(static_cast<const T&>(*this));}
};
class A : public CloneHelper<A>
{
virtual void Foo() { std::cout << 'A' << std::endl; }
};
class B : public CloneHelper<B>
{
virtual void Foo() { std::cout << 'B' << std::endl; }
};
class UniquePtrExample
{
std::unique_ptr<Interface> m_bar;
public:
UniquePtrExample() : m_bar(new A()){}
UniquePtrExample(const Interface& i) : m_bar(i.clone());
};
Note you can further extend the above to have a move variant of the clone function.