There is something that I don't manage to do with derived class.
Basically, I have one base class with an interact method, which takes another base class object as an argument. I then have a derived class, and I want it to overload the interact method - derived class objects should interact in their own style. So far so good, using virtual method I get the behaviour I want. However, I would also like to overload the interact method so it can take a derived class object as an argument.
Now, I have an object with a baseclass parameter. When I create such an object with a derived class as parameter and I make it interact with another object also created with a derived class as paramater, it does call the interact method of the derived class (as expected) but consider the method using the baseclass parameter. Is there a way to make it use the other method ?
The code is below, I hope this is clearer with it
#include <iostream>
class BaseClass{
public:
BaseClass();
virtual ~Baseclass();
virtual void interact(BaseClass* interaction_target){std::cout << "base class interaction" << std::endl;}
};
class DerivedClass : BaseClass{
public:
DerivedClass();
virtual ~DerivedClass();
virtual void interact(BaseClass* interaction_target){std::cout << "derived class interaction" << std::endl;}
virtual void interact(DerivedClass* interaction_target){std::cout << "interaction eased by the fact that two DerivedClass object are interacting" << std::endl;}
};
class MyObject{
protected:
BaseClass* interactor;
public:
MyObject(BaseClass* param) : interactor(param){}
virtual ~MyObject();
void ObjectInteraction(MyObject interaction_target){interactor->interact(interaction_target.interactor);}
};
int main(){
MyObject first_obj(new DerivedClass());
MyObject sec_obj(new DerivedClass());
first_obj.ObjectInteraction(sec_obj); // prints derived class interactions, whereas I would like
// it to use the second method ie. interact(DerivedClass*)
return 0;
}
Is there anyway to do this at all ?
Yes. What you're trying to do here is called "double dispatch," or more generally, "multiple dispatch." C++ doesn't support it directly (some languages do), but you can implement it yourself using the Visitor Pattern.
Related
I am attempting to do something like:
class Base {
public:
Base() {
cout << typeid(*this).name() << endl;
}
...
};
class Derived : public Base { ... }
class MoreDerived : public Derived { ... }
Derived d;
MoreDerived m;
Problem is, I always get Base printed to the screen, when I need to see Derived and MoreDerived. Is there a way to get typeid to work this way with derived classes? Or is there another approach besides typeid?
Note: I am adding functionality to an already coded suite, so I don't want to have to add a virtual method to the base class where the derived classes return this value themselves. Also, not worried about runtime overhead, this will be part of a debug compile switch.
In the constructor Base(), the object is still a "Base" instance. It will become a Derived instance after the Base() constructor. Try to do it after the construction and it will work.
See for example :
Avoiding virtual methods in constructor
Never Call Virtual Functions during Construction or Destruction
You can't do that from within a constructor (or destructor) - neither with typeid nor with a virtual method. The reason is while you're in a constructor the vtable pointer is set to the base class being constructed, so the object is of base class and no amount of polymorphism will help at that point.
You have to execute that code after the most derived class has been constructed. One option would be to use a factory function:
template<class T>
T* CreateInstance()
{
T* object = new T();
cout << typeid(*object).name() << endl;
return object;
}
Another option is to provide a virtual toName() function
struct Object{
virtual std::string toName() const = 0;
}
struct Base: Object{
std::string toName()const{ return "Base"; }
}
struct Derived: Base, Object{
std::string toName()const{ return "Derived"; }
This might get tedious since you need to manually create each toName function. But the advantage it gives you is to provide your own custom name.
I am trying to understand why the following code does not compile, apparently the solution relies in specifically declaring the dependency on method_A in the derived class.
Please refer to the following code:
class Base
{
public:
void method_A(int param, int param2)
{
std::cout << "Base call A" << std::endl;
}
};
//does not compile
class Derived : public Base
{
public:
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
//compiles
class Derived2 : public Base
{
public:
using Base::method_A; //compile
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
int main ()
{
Derived myDerived;
myDerived.method_A(1);
myDerived.method_A(1,2);
Derived2 myDerived2;
myDerived2.method_A(1);
myDerived2.method_A(1,2);
return 0;
}
"test.cpp", (S) The wrong number of arguments have been specified for "Derived::method_A(int)".
What is the technical reason that prevents the derived class to know its base class is implementing the method it's trying to overload?
I am looking in understanding better how the compiler/linker behaves in this case.
Its called Name Hiding. When you define a non virtual method with the same name as Base method it hides the Base class method in Derived class so you are getting the error for
myDerived.method_A(1,2);
To avoid hiding of Base class methods in Derived class use using keyword as you did in Derived2 class.
Also if you want to make it work you can do it explictly
myDerived.Base::method_A(1,2);
Check out this for better explanation why name hiding came into picture.
Well, for one you're calling
myDerived.method_A(1,2);
with 2 arguments, whereas both in base and derived the method is declared to take only one argument.
Secodnly, you're not overriding anything, because method_A is not virtual. You're overloading.
If your intention is to override void Base::method_A(int param, int param2) then you should mark it virtual in the base class:
virtual void method_A(int param, int param2)
Any function overriding this must have the same parameters and almost the same return type ('almost' loosely meaning that the differing return types must be polymorphically related, but in most cases it should have the identical return type).
All you're currently doing is overloading the function in the base class. The using keyword is bringing the base class function into the child class' namespace, as the language behaviour is not to do this by default.
I am currently trying to set a member of a class (myClass) to be some derived classes (Derived1, Derived2,...) of a Base class. Since the class don't know which derived class it is, the member type is set to Base class, it is only set to the derived class when constructed.
The derived classes all have a common member function which is implemented differently (Base class has a virtual version). However, when the this function is called from myClass, it always call the Base class version rather than the derived classes.
class Base
{
public:
Base(){}
virtual void who() { cout << "this is Base"; }
}
class Derived1 : public Base
{
public:
Derived1() : Base() {}
void who() { cout << "this is Derived1"; }
}
class myClass
{
private:
Base unknownDerived;
public:
myClass(const Base& inputDerived) { unknownDerived = inputDerived; }
void whosthere() { unknownDerived.who(); }
}
The output above is "this is Base", the Base class version is called instead.
Is there a way to include a member without specifying the actual derived class it is, but be able to call its specific function ( who() )?
thanks a lot!
When you declare Base as a member, Base is what you actually get. Even if you assign a Derived type to it, you experience what's called "slicing", where only the Base part of the derived object is copied, and your object is still a Base.
In C++, polymorphism only works through pointers and through references.
To make a real member object (not an indirection to the object) in myClass, you will need to make myClass have a template parameter, and you can decide at compile time what type it will be. Otherwise, you must use pointers and/or references.
Now you have to be clear about memory ownership, and proper cleanup. You may make the caller transfer the ownership of the object (by taking a unique_ptr) or you might insist that Base has a virtual clone() function to create a deep copy of the object. Further, you most likely will need a virtual destructor in your base class as well.
I am trying to understand why the following code does not compile, apparently the solution relies in specifically declaring the dependency on method_A in the derived class.
Please refer to the following code:
class Base
{
public:
void method_A(int param, int param2)
{
std::cout << "Base call A" << std::endl;
}
};
//does not compile
class Derived : public Base
{
public:
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
//compiles
class Derived2 : public Base
{
public:
using Base::method_A; //compile
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
int main ()
{
Derived myDerived;
myDerived.method_A(1);
myDerived.method_A(1,2);
Derived2 myDerived2;
myDerived2.method_A(1);
myDerived2.method_A(1,2);
return 0;
}
"test.cpp", (S) The wrong number of arguments have been specified for "Derived::method_A(int)".
What is the technical reason that prevents the derived class to know its base class is implementing the method it's trying to overload?
I am looking in understanding better how the compiler/linker behaves in this case.
Its called Name Hiding. When you define a non virtual method with the same name as Base method it hides the Base class method in Derived class so you are getting the error for
myDerived.method_A(1,2);
To avoid hiding of Base class methods in Derived class use using keyword as you did in Derived2 class.
Also if you want to make it work you can do it explictly
myDerived.Base::method_A(1,2);
Check out this for better explanation why name hiding came into picture.
Well, for one you're calling
myDerived.method_A(1,2);
with 2 arguments, whereas both in base and derived the method is declared to take only one argument.
Secodnly, you're not overriding anything, because method_A is not virtual. You're overloading.
If your intention is to override void Base::method_A(int param, int param2) then you should mark it virtual in the base class:
virtual void method_A(int param, int param2)
Any function overriding this must have the same parameters and almost the same return type ('almost' loosely meaning that the differing return types must be polymorphically related, but in most cases it should have the identical return type).
All you're currently doing is overloading the function in the base class. The using keyword is bringing the base class function into the child class' namespace, as the language behaviour is not to do this by default.
I am attempting to do something like:
class Base {
public:
Base() {
cout << typeid(*this).name() << endl;
}
...
};
class Derived : public Base { ... }
class MoreDerived : public Derived { ... }
Derived d;
MoreDerived m;
Problem is, I always get Base printed to the screen, when I need to see Derived and MoreDerived. Is there a way to get typeid to work this way with derived classes? Or is there another approach besides typeid?
Note: I am adding functionality to an already coded suite, so I don't want to have to add a virtual method to the base class where the derived classes return this value themselves. Also, not worried about runtime overhead, this will be part of a debug compile switch.
In the constructor Base(), the object is still a "Base" instance. It will become a Derived instance after the Base() constructor. Try to do it after the construction and it will work.
See for example :
Avoiding virtual methods in constructor
Never Call Virtual Functions during Construction or Destruction
You can't do that from within a constructor (or destructor) - neither with typeid nor with a virtual method. The reason is while you're in a constructor the vtable pointer is set to the base class being constructed, so the object is of base class and no amount of polymorphism will help at that point.
You have to execute that code after the most derived class has been constructed. One option would be to use a factory function:
template<class T>
T* CreateInstance()
{
T* object = new T();
cout << typeid(*object).name() << endl;
return object;
}
Another option is to provide a virtual toName() function
struct Object{
virtual std::string toName() const = 0;
}
struct Base: Object{
std::string toName()const{ return "Base"; }
}
struct Derived: Base, Object{
std::string toName()const{ return "Derived"; }
This might get tedious since you need to manually create each toName function. But the advantage it gives you is to provide your own custom name.