Today interviewer told me that Visitor pattern & double dispatch can be used to call non-virtual method of derived class from 3rd party library which source code can't be accessed/changed (this is what they do in their production code, he said).
For example, in below code they pass reference to Animal into Bar and call specific methods of classes derived from Animal without using dynamic_cast. Point is that dynamic_cast isn't used anywhere in their implementation. Templates aren't used.
I did rephrased my question to interviewer few times so there's no misunderstanding.
I don't see a way implementing Visitor without adding Accept method to classes in library that will utilize argument overloading on Visitor::Visit by passing *this to it.
Is this possible? Or interviewer confused it with other language that probably allow something C++ doesn't? Because he was emphasizing that Visitor and double dispatch is used together, whereas AFAIK in C++ double dispatch is Visitor, meaning Visitor is used to implement double dispatch. I hope I didn't lost you. Thanks for your time!
import <iostream>;
namespace LibraryCode // can't be changed
{
class Animal
{
public:
virtual ~Animal() = default;
public:
virtual void move() const { std::cout << "Animal: moving!" << std::endl; };
void breath() const { std::cout << "Animal: breathing!" << std::endl; }
};
class Duck : public Animal
{
public:
void move() const override { std::cout << "Duck: flying!" << std::endl; }
void make_nest() const { std::cout << "Duck: making nest!" << std::endl; }
};
class Dolphin : public Animal
{
public:
void move() const override { std::cout << "Dolphin: swimming!" << std::endl; }
void make_air_bubble() const { std::cout << "Dolphin: making air bubble!" << std::endl; }
};
}
void Bar(LibraryCode::Animal const& a)
{
a.breath();
a.move();
// w/o using dynamic_cast call make_nest if it's a Duck
// w/o using dynamic_cast call make_air_bubble if it's a Dolphin
}
int main()
{
Bar(LibraryCode::Duck{});
Bar(LibraryCode::Dolphin{});
}
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;
};
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've a parent class with 2 or more child class deriving from it. The number of different child classes may increase in future as more requirements are presented, but they'll all adhere to base class scheme and will contain few unique methods of their own. Let me present an example -
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class B{
private: int a; int b;
public: B(const int _a, const int _b) : a(_a), b(_b){}
virtual void tell(){ std::cout << "BASE" << std::endl; }
};
class C : public B{
std::string s;
public: C(int _a, int _b, std::string _s) : B(_a, _b), s(_s){}
void tell() override { std::cout << "CHILD C" << std::endl; }
void CFunc() {std::cout << "Can be called only from C" << std::endl;}
};
class D : public B{
double d;
public: D(int _a, int _b, double _d) : B(_a, _b), d(_d){}
void tell() override { std::cout << "CHILD D" << std::endl; }
void DFunc() {std::cout << "Can be called only from D" << std::endl;}
};
int main() {
std::vector<std::unique_ptr<B>> v;
v.push_back(std::make_unique<C>(1,2, "boom"));
v.push_back(std::make_unique<D>(1,2, 44.3));
for(auto &el: v){
el->tell();
}
return 0;
}
In the above example tell() method would work correctly since it is virtual and overrided properly in child classes. However for now I'm unable to call CFunc() method and DFunc() method of their respective classes. So I've two options in my mind -
either packup CFunc() and friends inside some already defined virtual method in child class so that it executes together. But I'll loose control over particular execution of unique methods as their number rises.
or provide some pure virtual methods in base class, which would be like void process() = 0 and let them be defined in child classes as they like. Would be probably left empty void process(){} by some and used by some. But again it doesn't feels right as I've lost return value and arguments along the way. Also like previous option, if there are more methods in some child class, this doesn't feels right way to solve.
and another -
dynamic_cast<>?. Would that be a nice option here - casting back parent's pointer to child's pointer (btw I'm using smart pointers here, so only unique/shared allowed) and then calling the required function. But how would I differentiate b/w different child classes? Another public member that might return some unique class enum value?
I'm quite unexperienced with this scenario and would like some feedback. How should I approach this problem?
I've a parent class with 2 or more child class deriving from it... But I'll loose control over particular execution of unique methods as their number rises.
Another option, useful when the number of methods is expected to increase, and the derived classes are expected to remain relatively stable, is to use the visitor pattern. The following uses boost::variant.
Say you start with your three classes:
#include <memory>
#include <iostream>
using namespace std;
using namespace boost;
class b{};
class c : public b{};
class d : public b{};
Instead of using a (smart) pointer to the base class b, you use a variant type:
using variant_t = variant<c, d>;
and variant variables:
variant_t v{c{}};
Now, if you want to handle c and d methods differently, you can use:
struct unique_visitor : public boost::static_visitor<void> {
void operator()(c c_) const { cout << "c" << endl; };
void operator()(d d_) const { cout << "d" << endl; };
};
which you would call with
apply_visitor(unique_visitor{}, v);
Note that you can also use the same mechanism to uniformly handle all types, by using a visitor that accepts the base class:
struct common_visitor : public boost::static_visitor<void> {
void operator()(b b_) const { cout << "b" << endl; };
};
apply_visitor(common_visitor{}, v);
Note that if the number of classes increases faster than the number of methods, this approach will cause maintenance problems.
Full code:
#include "boost/variant.hpp"
#include <iostream>
using namespace std;
using namespace boost;
class b{};
class c : public b{};
class d : public b{};
using variant_t = variant<c, d>;
struct unique_visitor : public boost::static_visitor<void> {
void operator()(c c_) const { cout << "c" << endl; };
void operator()(d d_) const { cout << "d" << endl; };
};
struct common_visitor : public boost::static_visitor<void> {
void operator()(b b_) const { cout << "b" << endl; };
};
int main() {
variant_t v{c{}};
apply_visitor(unique_visitor{}, v);
apply_visitor(common_visitor{}, v);
}
You can declare interfaces with pure methods for each device class. When you define a specific device implementation, you inherit only from the interfaces that make sense for it.
Using the interfaces that you define, you can then iterate and call methods which are specific to each device class.
In the following example I have declared a HardwareInterface which will be inherited by all devices, and an AlertInterface which will be inherited only by hardware devices that can physically alert a user. Other similar interfaces can be defined, such as SensorInterface, LEDInterface, etc.
#include <iostream>
#include <memory>
#include <vector>
class HardwareInteface {
public:
virtual void on() = 0;
virtual void off() = 0;
virtual char read() = 0;
virtual void write(char byte) = 0;
};
class AlertInterface {
public:
virtual void alert() = 0;
};
class Buzzer : public HardwareInteface, public AlertInterface {
public:
virtual void on();
virtual void off();
virtual char read();
virtual void write(char byte);
virtual void alert();
};
void Buzzer::on() {
std::cout << "Buzzer on!" << std::endl;
}
void Buzzer::off() {
/* TODO */
}
char Buzzer::read() {
return 0;
}
void Buzzer::write(char byte) {
/* TODO */
}
void Buzzer::alert() {
std::cout << "Buzz!" << std::endl;
}
class Vibrator : public HardwareInteface, public AlertInterface {
public:
virtual void on();
virtual void off();
virtual char read();
virtual void write(char byte);
virtual void alert();
};
void Vibrator::on() {
std::cout << "Vibrator on!" << std::endl;
}
void Vibrator::off() {
/* TODO */
}
char Vibrator::read() {
return 0;
}
void Vibrator::write(char byte) {
/* TODO */
}
void Vibrator::alert() {
std::cout << "Vibrate!" << std::endl;
}
int main(void) {
std::shared_ptr<Buzzer> buzzer = std::make_shared<Buzzer>();
std::shared_ptr<Vibrator> vibrator = std::make_shared<Vibrator>();
std::vector<std::shared_ptr<HardwareInteface>> hardware;
hardware.push_back(buzzer);
hardware.push_back(vibrator);
std::vector<std::shared_ptr<AlertInterface>> alerters;
alerters.push_back(buzzer);
alerters.push_back(vibrator);
for (auto device : hardware)
device->on();
for (auto alerter : alerters)
alerter->alert();
return 0;
}
Interfaces can be even more specific, as per individual sensor type: AccelerometerInterface, GyroscopeInterface, etc.
While what you ask is possible, it will either result in your code scattered with casts, or functions available on classes that make no sense. Both are undesirable.
If you need to know if it's a class C or D, then most likely either storing it as a B is wrong, or your interface B is wrong.
The whole point of polymorphism is that the things using B is that they don't need to know exactly what sort of B it is. To me, it sounds like you're extending classes rather than having them as members, ie "C is a B" doesn't make sense, but "C has a B does".
I would go back and reconsider what B,C,D and all future items do, and why they have these unique functions that you need to call; and look into if function overloading is what you really want to do. (Similar to Ami Tavory suggestion of visitor pattern)
you can use unique_ptr.get() to get the pointer in Unique Pointer,And the use the pointer as normall. like this:
for (auto &el : v) {
el->tell();
D* pd = dynamic_cast<D*>(el.get());
if (pd != nullptr)
{
pd->DFunc();
}
C* pc = dynamic_cast<C*>(el.get());
if (pc != nullptr)
{
pc->CFunc();
}
}
and the result is this:
CHILD C
Can be called only from C
CHILD D
Can be called only from D
You should use your 1st approach if you can to hide as much type-specific implementation details as possible.
Then, if you need public interfaces you should use virtual funtions (your 2nd approach), and avoid dynamic_cast (your 3rd approach). Many theads can tell you why (e.g. Polymorphism vs DownCasting). and you already mentioned one good reason, which is you shouldn't really check for the object type ...
If you have a problem with virtual functions because your drived classes have too many unique public interfaces, then it's not IS-A relationship and it's time to review your design. For example, for shared functionality, consider composition, rather than inheritance ...
There's been a lot of comments (in OP and Ami Tavory's answer) about visitor pattern.
I think it is and acceptable answer here (considering the OP question), even if visitor pattern has disadvantages, it also has advantages (see this topic: What are the actual advantages of the visitor pattern? What are the alternatives?). Basically, if you'll need to add a new child class later, the pattern implementation will force you to consider all cases where specific action for this new class has to be taken (compiler will force you to implement the new specific visit method for all your existing visitor child classes).
An easy implementation (without boost):
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class C;
class D;
class Visitor
{
public:
virtual ~Visitor() {}
virtual void visitC( C& c ) = 0;
virtual void visitD( D& d ) = 0;
};
class B{
private: int a; int b;
public: B(const int _a, const int _b) : a(_a), b(_b){}
virtual void tell(){ std::cout << "BASE" << std::endl; }
virtual void Accept( Visitor& v ) = 0; // force child class to handle the visitor
};
class C : public B{
std::string s;
public: C(int _a, int _b, std::string _s) : B(_a, _b), s(_s){}
void tell() override { std::cout << "CHILD C" << std::endl; }
void CFunc() {std::cout << "Can be called only from C" << std::endl;}
virtual void Accept( Visitor& v ) { v.visitC( *this ); }
};
class D : public B{
double d;
public: D(int _a, int _b, double _d) : B(_a, _b), d(_d){}
void tell() override { std::cout << "CHILD D" << std::endl; }
void DFunc() {std::cout << "Can be called only from D" << std::endl;}
virtual void Accept( Visitor& v ) { v.visitD( *this ); }
};
int main() {
std::vector<std::unique_ptr<B>> v;
v.push_back(std::make_unique<C>(1,2, "boom"));
v.push_back(std::make_unique<D>(1,2, 44.3));
// declare a new visitor every time you need a child-specific operation to be done
class callFuncVisitor : public Visitor
{
public:
callFuncVisitor() {}
virtual void visitC( C& c )
{
c.CFunc();
}
virtual void visitD( D& d )
{
d.DFunc();
}
};
callFuncVisitor visitor;
for(auto &el: v){
el->Accept(visitor);
}
return 0;
}
Live demo: https://ideone.com/JshiO6
Dynamic casting is the tool of absolute last resort. It is usually used when you are trying to overcome a poorly designed library that cannot be modified safely.
The only reason to need this sort of support is when you require parent and child instances to coexist in a collection. Right? The logic of polymorphism says all specialization methods that cannot logically exist in the parent should be referenced from within methods that do logically exist in the parent.
In other words, it is perfectly fine to have child class methods that don't exist in the parent to support the implementation of a virtual method.
A task queue implementation is the quintessential example (see below)
The special methods support the primary run() method. This allows a stack of tasks to be pushed into a queue and executed, no casts, no visitors, nice clean code.
// INCOMPLETE CODE
class Task
{
public:
virtual void run()= 0;
};
class PrintTask : public Task
{
private:
void printstuff()
{
// printing magic
}
public:
void run()
{
printstuff();
}
};
class EmailTask : public Task
{
private:
void SendMail()
{
// send mail magic
}
public:
void run()
{
SendMail();
}
};
class SaveTask : public Task
private:
void SaveStuff()
{
// save stuff magic
}
public:
void run()
{
SaveStuff();
}
};
Here's a "less bad" way of doing it, while keeping it simple.
Key points:
We avoid losing type information during the push_back()
New derived classes can be added easily.
Memory gets deallocated as you'd expect.
It's easy to read and maintain, arguably.
struct BPtr
{
B* bPtr;
std::unique_ptr<C> cPtr;
BPtr(std::unique_ptr<C>& p) : cPtr(p), bPtr(cPtr.get())
{ }
std::unique_ptr<D> dPtr;
BPtr(std::unique_ptr<D>& p) : dPtr(p), bPtr(dPtr.get())
{ }
};
int main()
{
std::vector<BPtr> v;
v.push_back(BPtr(std::make_unique<C>(1,2, "boom")));
v.push_back(BPtr(std::make_unique<D>(1,2, 44.3)));
for(auto &el: v){
el.bPtr->tell();
if(el.cPtr) {
el.cPtr->CFunc();
}
if(el.dPtr) {
el.dPtr->DFunc();
}
}
return 0;
}
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";
};
};