I am currently trying to switch the type of a derived class stored in a shared pointer to base class.
The problem is that the Derived class inherit from the Base class and is also templated as follow:
Base class:
#define PRINT(s) std::cout << s << std::endl
class Base {
public:
Base() : m_a(1) {}
virtual ~Base() = default;
virtual void print() { PRINT("BASE"); }
int m_a;
};
The derived class depend on an enumeration template:
enum eType { e0, e1 };
template<eType et>
class Derived : public Base { };
template<>
class Derived<e0> : public Base {
public:
Derived() { this->m_a = e0; }
void print() { PRINT("Derived e0, m_a value: " << e0 ); }
};
template<>
class Derived<e1> : public Base {
public:
Derived() { this->m_a = e1; }
void print() { PRINT("Derived e1, m_a value: " << e1 ); }
};
My objective is to have a shared pointer to the Base class so it would be possible to switch from the 2 derived classes as follow:
int main()
{
std::shared_ptr<Base> sp_00 = std::make_shared<Derived<e0>> ();
std::shared_ptr<Base> sp_01 = sp_00;
sp_01->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived<e1>> ();
*sp_01 = *sp_10;
sp_01->print();
sp_10->print();
}
The only problem as on the line *sp_01 = *sp_10; I expect that the pointer to base class switch from the derived type Derived<e0> to the derived type Derived<e1>. However in my example I get a different result for the line sp_01->print(); and the line sp_10->print(); indicating that sp_01 stays as a Derived<e0> type.
I want to avoid sp_01 = sp_10; because it will change the pointer. In the above example, it would lead to sp_00 != sp_01 and I want both sp_00 and sp_01 to share the same object.
I tried to replace the template derived class by a non template derived class as follow:
class Derived_e0 : public Base {
public:
Derived() { this->m_a = e0; }
void print() { PRINT("Derived e0, m_a value: " << e0 ); }
};
class Derived_e1 : public Base {
public:
Derived() { this->m_a = e1; }
void print() { PRINT("Derived e1, m_a value: " << e1 ); }
};
and the following code give the same result as the one with template.
int main()
{
std::shared_ptr<Base> sp_00 = std::make_shared<Derived_e0> ();
std::shared_ptr<Base> sp_01 = sp_00;
sp_01->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived_e1> ();
*sp_01 = *sp_10;
sp_01->print();
sp_10->print();
}
So my question is, how to switch the derived object pointed by a shared pointer without changing the shared_ptr itself (which is used in other part of the program ?)
Thanks, if you need any more information, please let me know
You cannot change the runtime type of sp_01 without re-assigning it because you cannot assign Derived<e1> to Derived<e0> (think of what would happen if these do not have the same size - you have allocated enough size for a Derived<e0>, not for a Derived<e1>!).
In my opinion, your design (or what you are trying to do with it) is flawed somewhere. However, if you really want to keep a "link" between sp_00 and sp_01, you probably need another "level" of pointer:
int main() {
std::shared_ptr<Base> *psp_01;
std::shared_ptr<Base> sp_00 = std::make_shared<Derived<e0>> ();
psp_01 = &sp_00;
(*psp_01)->print();
std::shared_ptr<Base> sp_10 = std::make_shared<Derived<e1>> ();
psp_01 = &sp_10;
(*psp_01)->print();
sp_10->print();
}
But again, I would analyze my design twice before using this.
You can dynamic_cast the raw pointer; something like
Derived* t = dymanic_cast<Derived*>(sp_00.get())
And you'll get NULL if it can't be cast, or a valid pointer if it can. That said, this requires RTTI to be built in, which will make your binary bigger, and needing to do this at all is a sign that your design isn't right.
Related
Suppose I have a base class that is an abstract interface, and two derived classes, which inherit a certain state from the base class. I want to change which derived class I'm using at run-time, but I want to preserve the shared state.
class Base{
public:
virtual void abstract() = 0;
SharedState ss;
};
class Der1 : public Base{
Der1() = default;
virtual void abstract() {//bla bla};
Der1(SharedState &s){
ss = s;};
};
class Der2 : public Base{
Der2() = default;
virtual void abstract(){//bla bla 2};
Der2(SharedState &s){
ss = s;};
};
struct SharedState{
int x,y,z;
float x1,y1,z1;
//etc...
}
I my handler code, I have a smart pointer that changes behaviour based on class type at run-time, hence the shared state constructor.
//driver code
std::unique_ptr<Base> ptr = std::make_unique<Der1>();
I'm planning to change the type, but with such a constructor I can preserve the state. However it is highly annoying to preface every member of the shared state with ss., is there a way to avoid this, perhaps with a using declaration of some sort?
Edit: I know I can move the shared state in the base and make it static, but that leads to performance drops when I'm not using this interface.
This is an ugly answer, but is an answer, solves the "ss" problem and can be usefull.
I overloaded the operator [] to directly return the values of your struct
struct SharedState{
int x,y,z;
float x1,y1,z1;
//etc...
};
class Base{
public:
virtual void abstract() = 0;
SharedState ss;
public:
int& operator[](const std::string rhs)
{
if(rhs == "x") //Here you will manage all the struct members, probably a map
return this->ss.x; // return the result by reference
}
};
class Der1 : public Base{
void abstract() override { };
public:
Der1(SharedState &s){
ss = s;};
};
class Der2 : public Base{
void abstract() override { };
public:
Der2(SharedState &s){
ss = s;};
};
int main()
{
SharedState ss;
ss.x = 100;
std::unique_ptr<Base> ptr = std::make_unique<Der1>(ss);
std::cout << (*ptr)["x"] << std::endl;
(*ptr)["x"] = 5; // You can change it too
std::cout << (*ptr)["x"] << std::endl;
std::unique_ptr<Base> ptr2 = std::make_unique<Der2>(ptr->ss);
std::cout << (*ptr2)["x"] << std::endl;
}
I haven't worked with derived classes and polymorphism in a while, and I can't figure out how to access a derived class data item.
// Quick example
class Base {
string data1; // data1 = "FOO"
};
class ChildA : public Base {
string data2;
};
int main() {
Base **list;
list = new Base*[1];
base[0] = new ChildA(// data2 = "BAR");
std::cout << base[0]->data1; // FOO
std::cout << base[0]->data2; // Error; no member named "data2" in Base
Is it possible to retrieve the derived data from the base class array?
When you're looking at an instance of a derived class through a pointer to the base class, you can only see the members of the base class, because generally, you wouldn't know what subtype instance you are looking at. The point of polymorphism and virtual functions is that in many cases, you can work with subtype instances without knowing their actual type. For instance, if you want to print information about an instance, and you want data2 to be included when you print a ChildA, you would create a virtual toString() function in Base and override it in ChildA to include data2. Then, you can call toString() without knowing the actual type, and if your instance is actually a ChildA, you'll get data2.
class member variable by default is private.
by using base class pointer, you can not get derived class member var at all.
If you would like to do so, you may want to implement virtual getter function, it will help you getting private member function from derived class.
If the base class interface must have knowledge of data potentially held in a derived class, here is one of the few ways that is not horribly dangerous.
#include <iostream>
#include <vector>
#include <utility>
#include <memory>
#include <stdexcept>
using namespace std;
class Base {
public:
Base(std::string d1 = {"FOO"} ) : _data1 { std::move(d1) } {}
virtual ~Base() = default; // because polymorphism without a virtual base class is naughty
const string& data1() const { return _data1; }
virtual bool has_data2() const { return false; }
virtual const string& data2() const {
throw invalid_argument {"I don't have data2"};
};
private:
string _data1; // data1 = "FOO"
};
class ChildA : public Base {
public:
ChildA(std::string d2, std::string d1 = {"FOO"})
: Base { std::move(d1) }
, _data2 { std::move(d2) }
{}
bool has_data2() const override { return true; }
const std::string& data2() const override {
return _data2;
};
private:
string _data2;
};
int main()
{
vector<unique_ptr<Base>> bases;
bases.push_back(unique_ptr<Base>(new ChildA("bob")));
bases.push_back(unique_ptr<Base>(new Base("not foo")));
for(const auto& p : bases) {
cout << p->data1() << ", " << (p->has_data2() ? p->data2() : "no data 2") << endl;
}
return 0;
}
So i have a vector<Base> and Base is the base class of multiple children, some of his children may be templated classes. I want to access the child classes from this base class without using dynamic_casting I cant also change the base class to an abstract class. Here is what I did
struct Ainterface {
virtual double GetVal() = 0;
};
struct Binterface {
virtual bool Getbo() = 0;
virtual int Getty() = 0;
};
struct Base {
Base(int id, Ainterface* inter):
id_(id),
a_interface_(inter){}
Base(int id, Binterface* inter):
id_(id),
b_interface_(inter){}
int id_;
Ainterface* a_interface_;
Binterface* b_interface_;
};
struct A : Base, Ainterface {
A():
Base(1, this),
val(5.5){}
double val;
double GetVal(){return val;}
};
template<typename T>
struct B : Base, Binterface {
B():
Base(2, this),
ty(5){}
int ty;
bool Getbo(){ return t_class.get();}
int Getty(){ return ty;}
T t_class;
};
...
...
int main(){
std::vector<Base> base;
base.push_back(A());
auto some = base.back();
switch (some.id_) {
case 1:
std::cout << some.a_interface_->GetVal() << std::endl;
break;
case 2:
std::cout << some.b_interface_->Getbo() << some.b_interface_->Getty() << std::endl;
default:
break;
}
return 0;
}
OUTPUT
5.5
Is this a safe thing to do?
Is there a better way to achieve this?
Thanks
When you declare a variable of type vector<Base>, the vector only allocates space for values of class Base, not any of the derived classes. When you push back a temporary A it is actually sliced and becomes a Base. The GetVal method only works by accident as the memory in which the temporary resided hasn't been reclaimed yet.
So, no, this is not a safe thing to do. It is undefined behaviour.
If you want to have a vector of objects that can vary in type, you have to use some kind of pointer. Ideally, you would use a vector<shared_ptr<Base>>.
I've got some problems with my lamba expressions: I have a class that owns a function pointer.
class SomeClass
{
void (*execFunc)(Base*);
}
And I have a Base class:
class Base
{
SomeClass* someClass;
void doSomething() { someClass->execFunc(this); }
}
From this one I derive lots of other classes whose execFuncs will be different. Therefore I want to use lambda-expressions; e.g:
class Derived final : public Base
{
int someDerivedAttrib;
static List<SomeClass*> someClasses = createSomeClasses(); // holds all possible
// SomeClasses for this
// derived class
static List<SomeClass*> createSomeClasses()
{
List<SomeClass*> scs;
SomeClass* sc = new SomeClass();
sc->execFunc = [] (Derived* derived) { derived->someDerivedAttrib = 10; };
scs << sc;
return scs
}
}
But unfornately this won't work since cast from void (*)(Derived*) to void (*)(Base*) is not possible. Any suggestions, except making a cast form Base* to Derived* in every lambda-function?
Expecting ye answers,
Albjenow
How about, instead of SomeClass being a regular class, making it a the base class of a class template that handles having the proper functor type, as well as downcasting to the right type ?
It would look like this:
class SomeClass
{
virtual void callFunc(Base*) = 0;
}
template<typename T>
class SomeDerivedClass : public SomeClass
{
static_assert(std::is_base_of<Base, T>::value, "SomeDerivedClass: unexpected base class");
virtual void callFunc(Base* b) override
{
execFunc(static_cast<T*>(b));
}
void (*execFunc)(T*);
}
Base then becomes:
class Base
{
SomeClass* someClass;
void doSomething() { someClass->callFunc(this); }
}
Then, in your Derived definition:
class Derived final : public Base
{
int someDerivedAttrib;
typedef SomeDerivedClass<Derived> tSomeClass;
static List<tSomeClass*> someClasses = createSomeClasses(); // holds all possible
// SomeClasses for this
// derived class
static List<tSomeClass*> createSomeClasses()
{
List<tSomeClass*> scs;
tSomeClass* sc = new tSomeClass();
sc->execFunc = [] (Derived* derived) { derived->someDerivedAttrib = 10; };
scs << sc;
return scs
}
}
However, this runs the risk of calling SomeDerivedClass::call with the wrong concrete class.
Wouldn't this do the trick?
sc->execFunc = [] (Base* base) { static_cast<Derived*>(base)->someDerivedAttrib = 10;
After all you have to respect the original signature of the execFunc pointer.
Setup
class Base
{
public:
Base();
virtual ~Base();
int getType();
protected:
int type;
};
class DerivedA : public Base
{
public:
DerivedA() { this->type = 1; };
~DerivedA();
int getA() { return 1;};
};
class DerivedB : public Base
{
public:
DerivedB() { this->type = 2; };
~DerivedB();
int getB() { return 2;};
};
Target
Having a vector containing objects of both derived classes and then be able to access child-specific methods.
Current "solution"
int main()
{
typedef boost::ptr_vector<Base> BasePtr;
BasePtr vec;
// Fill vec with some stuff
vec.push_back(new DerivedA());
vec.push_back(new DerivedB());
vec.push_back(new DerivedA());
vec.push_back(new DerivedB());
typedef BasePtr::iterator BaseIter;
for ( BaseIter it = vec.begin(); it != vec.end(); it++ ) {
if (it->getType() == 1) {
std::cout << it->getA() << '\n';
} else {
std::cout << it->getB() << '\n';
}
}
return 0;
}
Problem
Obviously "it" is not recognised as either DerivedA or DerivedB, so the child-specific method cant be accessed.
Some form of cast is required, so i guess the question is:
How do I properly cast the iterator to the correct derieved class?
Maybe there is a better way to structure this whole scenario?
Edit:
Seems i was a bit unclear. The purpose of the methods in the derived classes is fundamentally different.
Consider the base class Item that have the derived classes Armor and Weapon.
In this example you can see why, for instance, Weapon have a function getDamage() that maybe returns a float.
This function is not needed for Armor and dosn't even have anything similar.
In this example you can see the vector as an Inventory that can contain any number, and types, of items. Maybe even items that have a stack and some use (Potions maybe)
If you have to cast to derived, then it means you have a broken design.
But if you really have to then this would do (put it in the for loop) :
DerivedB * typeB = dynamic_cast< DerivedB * >( &*it );
if ( typeB != nullptr )
{
std::cout << typeB->getB() << '\n';
}
A better approach would be to add getB() to the interface, and implement it in DerivedA (it can return some dummy value, or throw if really needed).
Casting is a pretty ugly solution, and not very C++'y. Instead you should be using virtual functions.
Something like:
class Base
{
public:
virtual int get() = 0;
// ...
};
class DerivedA : public Base
{
public:
int get() { return 1;};
};
class DerivedB : public Base
{
public:
int get() { return 2;};
};
Then there is no need to have an extra type, and you can just call it->get();.
You can use dynamic_cast as below.
for ( BaseIter it = vec.begin(); it != vec.end(); it++ )
{
DerivedA* dA = dynamic_cast<DerivedA*>(it);
if(dA != NULL)
{
// Do whatever for DerivedA
}
// Similarly check for DerivedB
}
There is no easy way out here other than designing your interfaces to utilize the polymorphism. i.e, define function signatures in the base class and implement them in the derived class. The for-loop above, ideally shouldn't try to know what is the type of the container items. It is impossible to comment on this without knowing what is the real functions represented by getA() and getB().