Okay, so to illustrate the issue I am having I will show some (pseudo) code.
Lets say I have the following models:
class Animal : public GameObject;
class Player : public GameObject;
class GameObject : public ObjectInterface;
class ObjectInterface
{
public:
virtual ~ObjectInterface() = default;
virtual vec3 GetPosition() = 0;
}
Now I also hold some "object context", which holds collections of certain game objects.
class ContextObject
{
// they implement ObjectInterface
vector<shared_ptr<Animal>> animals;
vector<shared_ptr<Player>> players;
}
Now I have a TargetSelector class, which works directly with the ObjectInterface only.
class TargetSelector
{
// this is somehow not possible, although `animals` are a subclass of `ObjectInterface`
vector<shared_ptr<Model::ObjectInterface>>& GetAvailableTargets()
{
return context->animals; // context is some `ObjectContext`
}
}
I would expect the above code to work, since an Animal is of the type ObjectInterface. But instead I get an error saying it cannot convert from an vector<shared_ptr<Animal>> to an vector<shared_ptr<ObjectInterface>>. Is this even suppose to work?
Could someone explain me why I cannot do this kind of polymorphism and if possible a nice solution so I can make this work.
Thanks, any help is appreciated!
I would expect the above code to work, since an Animal is of the type ObjectInterface.
Unfortunately, class templates don't work that way.
Given
struct Base {};
struct Derived : Base {};
Derived d;
Base& bref = d; // OK.
Base b = d; // OK.
However, given
template <tpename T> Foo {};
Foo<Derived> d;
Foo<Base>& bref = d; // Not OK
Foo<Base> b = d; // Not OK.
Derived is a sub-type of Base does not imply Foo<Derived> is a sub-type of Foo<Base>.
That analogy applies to shared_ptr too. Your problem is compounded by use of another layer of class template. shared_ptr<Derived> is not a sub-type of shared_ptr<Base>. Never mind being able to use vector<shared_ptr<Derived>> when a vector<shared_ptr<Base>> is exepcted.
You can use vector<shared_ptr<ObjectInterface>> in all the places and make sure to cast to the appropriate shared_ptr type before using it.
Check out the various pointer_cast functions at http://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast.
Related
I want to retrieve the initial type in the base class A because the method encodeMsg() will have tasks that are related to the derived type
#include "stdafx.h"
#include <iostream>
struct base {
};
struct derive : base {
};
class A{
public:
A(){}
virtual void encode() {
encodeMsg(_bStruct);
// here I want to cast base to derive but I don't know how I tried
// static_cast<decltype(this)>(_bStruct) but it seems doesn't work
}
virtual void setStruct(base* bStruct) {
_bStruct = bStruct;
}
private:
virtual void encodeMsg(base* bStruct) = 0;
protected:
base* _bStruct;
};
class B : public A {
public:
B(){}
void encodeMsg(base* bStruct) {
derive* _dStruct = static_cast<derive*>(bStruct);
// ..
// stuff within dervied struct
_bStruct = static_cast<base*>(_dStruct); // turn back to base struct
}
};
int main() {
B b;
base* _bStruct = new derive();
b.setStruct(_bStruct);
b.encode();
return 0;
}
The question makes no sense.
In your code, the only thing you could do with the pointer, if you could create it, is access members known to be in the base class. But you can do that already without the pointer. So what purpose does the pointer serve?
If you want to one thing if it's a derived1 and something else if it's a derived2, then you need to use one piece of code for the derived1 case and one piece of code for the derived2 case.
If you want to do the same thing regardless of what derived type it is, there is no need for the cast you seek. The code in this function will be the same regardless of what the derived type is.
If you want code that only works if the derived type is some specific type, use a dynamic_cast to a pointer to that type and write the specific code. If you want code that works regardless of the derived type, use a pointer to an instance of the base class.
Update:
To access members not in base but in a derived1, use this code:
virtual void encode() {
derived1* d1 = dynamic_cast<derived1*>(bStruct);
if (d1 != nullptr)
{
// here you can access d1->whatever
}
}
I have a super Class (A) and two sub Class (B ,C)
an abstract Function in A have two difference return type in B and C!
How i have to Declare these??
return type is important
class A { //Super Class
public:
A();
virtual (some Type) QWERTY() = 0;
};
class B : public A { //Sub Class
public:
B();
double QWERTY();
};
class C : public A { //Sub Class
public:
C();
unsigned int QWERTY();
};
i'v to call sub Class function with super Class pointer
Since the functions are different in each sub-classes, you'll have to access them from pointers to those sub-classes.
This is exactly the kind of situation where dynamic_cast<> can help: it can conditionally convert a pointer from a base class to a sub-class if and only if it happens to be of the correct type:
void foo(A* a_ptr) {
B* b_ptr = dynamic_cast<B*>(a_ptr);
C* c_ptr = dynamic_cast<C*>(a_ptr);
if(b_ptr) {
b_ptr->QWERTY();
}
if(c_ptr) {
c_ptr->QWERTY();
}
}
It's, however, worth mentioning that this is some pretty ugly code, and might be suitable to solve the quiz you are presenting us, but in a normal environment, there are some design reevaluation that would happen before going to implement things this way.
How can I get derived class object from my generic interface pointer.
I do not want to type cast the generic interface in order to achieve above .
e.g:
class Base {}; // Has pure virtual functions and is my interface class
class Derived : public Base {}; // Additional functions .
Base *b = new Derived();
Now, I want to get derived pointer Derived *derived from b without casting.
How can I achieve this?
Your setup seems strange, I'd look for alternative options like returning Derived directly or moving the functions you need into base since you seem to need them.
If you still want to do that you could have something like:
class Derived; // Forward declaration
class Base {
public:
virtual Derived* as_derived() { return null; }
...
};
class Derived : public Base {
public:
Derived* as_derived() override { return this; }
};
Still, this looks like a hack and I would suggest casting instead. At least casting it's a common pattern and it will be easier for others to understand.
Is it an O.K. design if i return an instance of Derived class from Base class member function(created using new Derived()) ?
Also this involves the need to forward declare the Derived class and also make the Derived class constructor public.
Code Sample :-
Class Base
{
public:
Base() {}
Derived* get_new_derived(int X)
{
Derived *der = new Derived(X);
return der;
}
}
Class Derived : public Base
{
private:
int _X;
protected:
Derived(int X) { _X = X; }
public:
Derived* get_new_derived(int X)
{
Derived *der = new Derived(X);
return der;
}
}
I have one more derived class(say Derived1). Now let's say :-
Usage1 :
Derived1* der1 = new Derived1();
Derived * der = der1->get_new_derived(10);
Usage2 :
Derived1* der1 = new Derived1();
Base* bs = der1;
Derived * der = bs->get_new_derived(10);
In the general case, this usually indicates bad design - a base class shouldn't normally know/care about its derived classes.
Note that you can return a pointer to Derived typed as Base* - that's the principle of the Factory Method design pattern. Perhaps this fits your actual scenario?
Note however that all rules have exceptions. If your (base class + derived classes) represent a tighly coupled and coherent unit (such as a Tree interface with two subclasses FastTree and SmallTree, optimised for different purposes), it is acceptable for them to be aware of each other, and Tree defining such functions as:
std::unique_ptr<SmallTree> Tree::createSmallCopy() const
{
return { new SmallTree(/*args*/) };
}
std::unique_ptr<FastTree> Tree::createFastCopy() const
{
return { new FastTree(/*args*/) };
}
So it depends on your actual use case. I'd generally be wary of such design, it but it has its uses.
As a side note, in modern C++, you should never use an owning raw pointer - use a smart pointer like std::unique_ptr or boost::shared_ptr.
How about this?
// The Curiously Recurring Template Pattern (CRTP)
template<class Derived>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Yes you can do it. The question is whether you should.
You shouldn't do it since it implies Base knows Derived which isn't proper object oriented design. The dependencies should be one way - derived knows the Base and not vice versa.
How do you design polymorphism when you have a member which type depends on some constraints.
Say I have this :
template<typename T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
T member;
};
class DerivedA : public Base<int>
{
public:
DerivedA() {member = 5;}
};
class DerivedB : public Base<float>
{
public:
DerivedB() = default;
};
I want to be able to create a new derived object depending on different parameters, i.e :
Base *b;
if (something)
b = new DerivedA();
else
b = new DerivedB();
Obviously I can't do this since I need to provide template parameters for the declaration of b.
Is this bad design ? How do you handle this ?
I could write a small wrapper :
class Wrapper() {};
template<typename T>
class Base : public Wrapper
{
// ...
};
Wrapper a, b;
a = new DerivedA;
b = new DerivedB;
But then I won't have access directly to member or other methods declared in Base or Derived. I would need to cast : reinterpret_cast<DerivedA*>(a)->member, making polymorphism useless.
Thanks
Wrapper design should be exactly what you are looking for. The problem is that c++ is statically typed, so you can't declare member without specifying its type. The common way to avoid this is to design a base class which supports all the functionality you want, and implement a specific behaviour in derived classes, just as you did.
Probably the problem is that your class doesn't support all the functionality you need. Try to avoid using member directly and wrap its usage into virtual methods. Reimplement these methods in your derived classes.
If this is still not an option, consider methods for extracting your member. Maybe virtual getters and setters with appropriate conversions.
As a last resort, consider boost::variant, boost::any. But really they are implemented using the technique similar to your wrapper. So you get wrapper for the wrapper.
Well, if the "access" depends on the template parameter T (such reading Base.member), then you have to supply it somehow. Casting to one of the derived classes is one way to do it, but you don't need the reinterpret_cast. You need to start using pointers/references, to avoid the cut-off and let the substitutability work correctly:
Wrapper *a, *b;
a = new DerivedA;
b = new DerivedB;
int a_member = static_cast<DerivedA*>(a)->member;
float b_member = static_cast<DerivedB*>(b)->member;
And if you add a virtual method to Wrapper to make it polymorphic, you can do dynamic cast as well:
DerivedB* b_derived = dynamic_cast<DerivedB*>(b);
if (b_derived != nullptr) {
float b_member = b_derived->member;
// ...
}