Accessing method of derived class when using ptr_vector - c++

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().

Related

How to get access to the derived std::shared_ptr?

Suppose I have code like that one, and I want to get access to the myClassB members. How can I do that? I need to use the functionality of functionA.
I can't change it because it is from the 3rd party library. And I need to use functionA to create it, and get values created by it. In this case "Test_1" string
class myClassA {
public:
myClassA(){}
~myClassA(){}
};
class myClassB : public myClassA
{
public:
myClassB(){}
void setString1(std::string newString)
std::string getS1()
private:
std::string privateMember;
};
std::shared_ptr<myClassA> functionA()
{
std::shared_ptr<myClassB> temporary(new myClassB());
temporary->setString1("TEST_1");
return std::move(temporary);
}
int main()
{
std::shared_ptr<myClassA> myPtr; // = functionA(); ??
}
Theoretically, you could use a dynamic_cast (or in this case specifically, std::dynamic_pointer_cast to get the derived pointer type. Like so:
std::shared_ptr<MyClassA> a_ptr = functionA();
std::shared_ptr<MyClassB> b_ptr = std::dynamic_pointer_cast<MyClassB>(a_ptr);
if(b_ptr) {//Check to verify the cast was successful
b_ptr->setString("Test1");
}
There is, however, a major caveat to this. In order for dynamic_cast (and therefore std::dynamic_pointer_cast) to work, your object hierarchy must have a virtual table defined. That means at least one of the methods defined by MyClassA must be declared virtual. The simplest solution is to declare the destructor virtual, since that's good practice whenever you're defining polymorphic objects (since you need it to ensure that any derived classes clean up their resources correctly).
class MyClassA {
public:
MyClassA() = default;
virtual ~MyClassA() = default;
};
Agree with dynamic_cast but without a virtual function table in ClassA, something like this would have to do:
Test This Code
#include <string>
#include <memory>
#include <iostream>
#include <set>
class myClassA {
public:
myClassA(){}
~myClassA(){}
};
class myClassB;
class ClassB_Registry{
private:
ClassB_Registry(){
}
~ClassB_Registry(){
}
public:
static ClassB_Registry* Get(){ static ClassB_Registry obj; return &obj; }
static void Register(myClassB* ptr){
Get()->mPointers.insert(ptr);
}
static void UnRegister(myClassB* ptr){
Get()->mPointers.erase(ptr);
}
static myClassB* Cast(myClassA* ptr){
if(Get()->mPointers.count((myClassB*)ptr) > 0) return (myClassB*)ptr;
return nullptr;
}
private:
std::set<myClassB*> mPointers;
};
class myClassB : public myClassA
{
public:
myClassB(){ ClassB_Registry::Register(this); }
~myClassB(){ ClassB_Registry::UnRegister(this); }
void setString1(std::string newString){privateMember = newString;}
std::string getS1() { return privateMember; }
private:
std::string privateMember;
};
std::shared_ptr<myClassA> functionA()
{
std::shared_ptr<myClassB> temporary(new myClassB());
temporary->setString1("TEST_1");
return std::move(temporary);
}
int main()
{
std::shared_ptr<myClassA> myPtr = functionA(); //??
std::shared_ptr<myClassA> myPtr_a(new myClassA()); //??
myClassB* pDerrived = ClassB_Registry::Cast(myPtr.get()); // bridge the RTTI gap
if(pDerrived)
std::cout << pDerrived->getS1();
pDerrived = ClassB_Registry::Cast(myPtr_a.get()); // works on A pointers to return null
if(pDerrived)
std::cout << pDerrived->getS1() << " \n";
else
std::cout << "Not A Pointer of Type B" << " \n";
}
It's not pretty, but if myClassB had a virtual table as mentioned previously, and all future derived classes used myClassB as the base, then you could bridge the gap for RTTI.

Switch Derived class of a shared pointer to base class

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.

C++ What is the expected behavior of passing a 'this' pointer to a base class and then store it in as another base class of the child class

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>>.

Passing around base class pointers

Scenario: I have the following defined classes.
class Baseclass { };
class DerivedTypeA : public Baseclass { };
class DerivedTypeB : public Baseclass { };
// ... and so on ...
class Container
{
list<Baseclass*> stuff;
list<DerivedTypeA*> specific_stuff;
// ... initializing constructors and so on ...
public:
void add(Baseclass * b)
{
stuff.add(b);
}
void add(DerivedTypeA * a)
{
stuff.add(a);
specific_stuff.add(a);
}
};
class ContainerOperator
{
Container c;
// ... initializing constructors and so on ...
public:
void operateOnStuff(Baseclass * b)
{
// This will always use "void add(Baseclass * b)" no matter what object b really is.
c.add(b);
}
};
// ...
containerOperator.operateOnStuff(new DerivedTypeA());
So, what I want to do is to handle a certain derived class in some special way in Container.
Problem: void add(DerivedTypeA * a) is never called. I'm obviously doing something wrong. What is the correct way of doing what I am trying to achieve here?
Overload resolution in C++ happens at compile-time, not run-time. The "usual" way to solve problems like this is to use Visitor pattern.
You can reduce the amount of boilerplate copy-paste by implementing Visitor with CRTP.
If you use CRTP for Base::accept, you don't need to define it any more in derived classes.
Here is a similar program to yours, but a little simpler:
#include <iostream>
class Base; class Derived;
struct Operation {
void add(Base *b) {
std::cout << "Base\n";
}
void add(Derived *b) {
std::cout << "Derived\n";
}
void visit(Base *b); // need to define this after Base class
};
struct Base {
virtual ~Base() {}
virtual void accept(Operation &o)
{
o.add(this);
}
};
void Operation::visit(Base *b) {
b->accept(*this);
}
struct Derived : public Base {
void accept(Operation &o)
{
o.add(this);
}
};
int main() {
Operation o;
Base b;
Derived d;
Base *ptrb = &b;
Base *ptrd = &d;
o.add(ptrb); // These two print "Base"
o.add(ptrd);
o.visit(ptrb); // "Base"
o.visit(ptrd); // "Derived"
}
You can use RTTI to determine whether the provided object is of the derived type, and if so, call the second add() function.
void add(Baseclass * b)
{
stuff.add(b);
DerivedTypeA * a = dynamic_cast<DerivedTypeA *>(b);
if ( a != 0 )
specific_stuff.add(a);
}
Unlike the visitor pattern this solution violates the Open-Closed Principle, but it's a lot simpler and easier to understand when the number of derived classes do not change or change slowly over time.

Determining size of a polymorphic C++ class

Using the sizeof operator, I can determine the size of any type – but how can I dynamically determine the size of a polymorphic class at runtime?
For example, I have a pointer to an Animal, and I want to get the size of the actual object it points to, which will be different if it is a Cat or a Dog. Is there a simple way to do this, short of creating a virtual method Animal::size and overloading it to return the sizeof of each specific type?
If you know the set of possible types, you can use RTTI to find out the dynamic type by doing dynamic_cast. If you don't, the only way is through a virtual function.
Or you can use typeid, which might be faster than dynamic_cast (also with dynamic_cast you can cast to intermediary types in the hierarchy).
It looks rather bad:
#include <iostream>
#include <typeinfo>
class Creature
{
char x[4];
public:
virtual ~Creature() {}
};
class Animal: public Creature { char x[8];};
class Bird: public Creature { char x[16]; };
class Dog: public Animal { char x[32]; };
class Cat: public Animal { char x[64]; };
class Parrot: public Bird { char x[128]; };
unsigned creature_size(const Creature& cr)
{
if (typeid(cr) == typeid(Animal)) {
return sizeof (Animal);
}
else if (typeid(cr) == typeid(Dog)) {
return sizeof(Dog);
}
else if (typeid(cr) == typeid(Cat)) {
return sizeof(Cat);
}
else if (typeid(cr) == typeid(Bird)) {
return sizeof(Bird);
}
else if (typeid(cr) == typeid(Parrot)) {
return sizeof(Parrot);
}
else if (typeid(cr) == typeid(Creature)){
return sizeof(Creature);
}
assert(false && "creature_size not implemented for this type");
return 0;
}
int main()
{
std::cout << creature_size(Creature()) << '\n'
<< creature_size(Animal()) << '\n'
<< creature_size(Bird()) << '\n'
<< creature_size(Dog()) << '\n'
<< creature_size(Cat()) << '\n'
<< creature_size(Parrot()) << '\n' ;
}
For each new type you'll need to add code to the creature_size function. With a virtual size function you'll need to implement this function in each class as well. However, this function will be significantly simpler (perfectly copy-n-pasteable, which shows there might be both a limitation in the language and a problem with your code design):
virtual unsigned size() const { return sizeof(*this); }
And you can make it abstract in the base class which means that it will be a compiler error if you forget to override this method.
Edit: this is naturally assuming that given any Creature you want to know its size. If you have a strong reason to believe that you are dealing with a Dog - or a subclass of Dog (and you don't care if it is a subclass), then naturally you can use dynamic_cast for an ad hoc test.
If you are able to change source classes' design, you can totally replace dynamic polymorphism (which uses virtual functions) with static polymorphism and use the CRTP idiom:
template <class TDerived>
class Base
{
public:
int getSize()
{ return sizeof(TDerived); }
void print()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
int some_data;
};
class Derived : public Base<Derived>
{
public:
int some_other_data1;
int some_other_data2;
};
class AnotherDerived : public Base<AnotherDerived>
{
public:
int getSize()
{ return some_unusual_calculations(); }
// Note that the static_cast above is required for this override to work,
// because we are not using virtual functions
};
int main()
{
Derived d;
d.print();
AnotherDerived ad;
ad.print();
return 0;
}
You can do this when the needed polymorphic behavior of program can be determined at compile-time (like the sizeof case), since the CRTP has not the flexibility of dynamic polymorphism to resolve the desired object at run-time.
The static polymorphism also has the advantage of higher performance by removing virtual-function-call overhead.
If you don't want to templatize Base class or you need to hold different derived instances of Base class in a same location (like an array or a vector), you can use CRTP on a middle class and move the polymorphic behavior to that class (similar to the Polymorphic copy construction example in the Wikipedia):
class Base
{
public:
virtual int getSize() = 0;
void print()
{
std::cout << getSize() << std:endl;
}
int some_data;
};
template <class TDerived>
class BaseCRTP: public Base
{
public:
virtual int getSize()
{ return sizeof(TDerived); }
};
class Derived : public BaseCRTP<Derived>
{
// As before ...
};
class AnotherDerived : public BaseCRTP<AnotherDerived>
{
// As before ...
// Note that although no static_cast is used in print(),
// the getSize() override still works due to virtual function.
};
Base* obj_list1[100];
obj_list1[0] = new Derived();
obj_list1[2] = new AnotherDerived();
std::vector<Base*> obj_list2;
obj_list2.push_back(new Derived());
obj_list2.push_back(new AnotherDerived());
--
Update: I now found a similar but more detailed answer on stackoverflow which explains that if we further derive from the derived classes above (e.g. class FurtherDerived : public Derived {...}), the sizeof will not report correctly. He gives a more complex variant of the code to overcome this.
I can't believe that somebody's invented type_id() instead of implementing proper traits ....
One slightly convoluted way that will also work is to implement this through a Curiously Recurring Template Pattern
#include <iostream>
class Base {
public:
virtual ~Base() {}
virtual size_t getSize() = 0;
};
template <class T>
class BaseT : public Base {
public:
size_t getSize() override { return sizeof(T); }
};
class Child : public BaseT<Child> {};
int main()
{
std::unique_ptr<Base> child(new Child);
std::cout << child->getSize();
}