I'm using an std::map for storage (storing data on the stack).
This map is happened to store items which are derived instances of a base class:
class Base {
public:
int id;
Base(int id): id(id) {}
void baseFn() {}
};
class Derived : public Base {
public:
Derived(int id): Base(id) {}
};
std::map<int, Derived> storage;
My question is more theoretical than practical (as I know a few solutions):
I have to pass this storage to a function (register_cb) requires void* as its parameter. This function is not owned by me, and I can't change it.
Later, a callback function (cb) will pass me this pointer, and I wish to use it to get back my storage:
//void register_cb(void* data);
register_cb(&storage);
void cb(void* data) {
//get back my storage
std::map<int, Derived>* storage = static_cast<std::map<int, Derived>*>(data);
}
Now this is a bit ugly, but anyway it works.
What I wish to accomplish is to access the storage from callbacks where I don't know the Derived class, only the Base:
I wish to iterate through the map, and call baseFn on every single item. Can I somehow safely cast std::map<int, Derived> to std::map<int, Base pointer or reference or whatever>?
Related
If I have a base class, and a templated derived class, how can I access the stored value in the derived class using a pointer to the base class?
class base {
public:
virtual auto get();
};
template <typename T>
class derived : public base {
public:
derived(T val) {m_val = val}
~derived(){}
auto get(){
return m_val;
}
private:
m_val;
};
This obviously errors out, as you can't have a virtual auto/template function.
My main motivation is to elsewhere have something like
std::vector<base*> v;
and be able to access values like
return v.at(2)->get(); // calls overridden get and returns m_val of the appropriate type
Currently stuck on how to get around this. I'm more interested in being able to store a vector of pointers to base and accessing things like I showed, even if it means mangling class structure.
I'm trying to implement something following the decorator pattern, but I cannot seem to obtain from a shared_ptr the same run-time behaviour I can get through normal pointers.
I have a basic class I (interface) with a virtual method, then I derive from it two classes:
class A (component) which will contain some data
class B (decorator) which derives from I and also contains a pointer to it and will implement some additional behaviour. I have a constructor that initialises the pointer to a certain I (or derived) object.
Then I want to be able to build a B object with its pointer pointing to an A, so that when I call the common methods I call the A ones not the I ones.
I can do this if I make the pointer in B in the usual way (in the code example, see the class B_basic and the object bb in the main).
But if I make this pointer like a shared_ptr to I it calls the method from I even if I build it pointing to an actual A (in code see the B_shared class and the object bs)
class I {
public:
virtual void method() {cout<<"I\n";}
virtual ~I() = default;
};
class A : public I {
public:
virtual void method() {cout<<"A\n";}
};
class B_shared : public I {
public:
shared_ptr<I> shared_pointer;
B_shared(const I& i) : shared_pointer(make_shared<I>(i)) {}
virtual void method() {
cout<<"B_shared > ";
shared_pointer->method();
}
};
class B_basic : public I {
public:
I* basic_pointer;
B_basic(I* i) : basic_pointer(i) {}
virtual void method() {
cout<<"B_basic > ";
basic_pointer->method();
}
};
int main() {
A a;
B_shared bs(a);
B_basic bb(&a);
bs.method(); // B_shared > I
bb.method(); // B_basic > A
}
What am I doing wrong?
This is object slicing.
In the following line you make a copy of the instance i of type A to type I. Thus the original type A is sliced to base type I.
shared_pointer(make_shared<I>(i))
In raw pointer version basic_pointer(i), you save the pointer itself, no slicing.
(C++) Suppose I have two classes A and B. Class B has a pointer to class A along with a method. How exactly do I interpret what's going on in this case. When that method is called does it have access to the methods in Class A since it's pointing to a possible instance of A
Class A {
public:
void method1() const;
void method2() const;
}
Class B {
public:
A* method3(int);
void method4();
void method5();
}
Let me know if I'm being vague here or need to provide more info
Edit 1: So basically Class B creates objects that get stored in a map that is accessible by an integer key. Class A has methods that can manipulate any one of those individual objects. So I guess in this case method3() would take in the key of the map as input and then it fetches that object from the map and then the user can choose to do method1 or method2 from Class A to manipulate it.
i.e. The object being stored in the map could be like a game piece and the methods in Class A can like flip it or rotate it.
Why don't you just try it?
class A {
public:
void method1() const;
void method2() const;
}
class B {
public:
A *GetA(int i) { return &mapA[i];
void method3();
private:
std::map<int, A> mapA;
}
int main()
{
B b;
auto pA = b.Get(1);
pA->method1();
return 0;
}
As long as A has a default constructor, this should create new items in B's map if they don't exist.
Note that making class A method1 and method2 const means that they don't change anything in A, so they couldn't be functions which change any of A's state.
The member function A* method3(int) is going to return a pointer to an instance of the class A. Thus the compiler will reserve a proper amount of memory for it on the heap. Most probably you will need to create dynamically an instance of that class inside the function method3 and return the pointer pointing to it.
I have a base class and several derived classes. The base class looks like this:
class Base
{
int type; //the derived type the object belongs to
int nOfChildren;
Base** children; //each child can be any of the derived types
...
}
Now I need to duplicate an instance of Base. Because of the recursion, a virtual method Base::duplicate() is needed. It also seems clear what should go in it:
Base temp = new Base();
temp->type = temp;
temp->nOfChildren = nOfChildren;
temp->children = new Base*[nOfChildren];
beyond that, it's not so clear.
Do I allocate each temp->children[i] as a Base object or as a derived object? Do I need a case statement to cater to all possible derived types? Do I need to implement a duplicate() method for each derived type, even those that contain no other information than the Base class? (If a derived class contains more information, then it is clear that I need a separate mechanism. There are several derived classes that contain no further data than the base, although they contain different implementations of a handler() method not shown.)
You are right, a virtual method is needed for cloning the polymorphic object. OTOH, you can leverage C++ features to simplify writing it:
class Child : public ICloneable {
public:
// stuff...
Child *clone() const { return new Child(*this); }
}
Also, don't put collections of objects into arrays! Use std::vector instead.
class Base
{
// stuff...
std::vector<Base*> children;
}
Even better, use a smart pointer to wrap the cloning operation into an object std::vector will be able to manage transparently.
template<typename T>
struct clone_ptr {
T *object;
clone_ptr() : object(new T()) {}
clone_ptr(T *object_) : object(object_) {}
clone_ptr(clone_ptr<T> const &other) : object(other.object->clone()) {}
clone_ptr<T> &operator=(clone_ptr<T> other) {
std::swap(object, other.object);
return *this;
}
~clone_ptr() { delete object; }
};
That way you can just use a std::vector of clone_ptrs into your Base:
class Base
{
// stuff...
std::vector<clone_ptr<Base>> children;
}
Each object will be automagically copied into an object of the same polymorphic type, as long as you implement clone() in each class. The vector will be cloned in the same way other data members are, automatically by the C++ compiler.
OK, Not sure on the terminology for what I'm trying to do so edits are very welcome.
I've got code such as this:
class CBaseItemTracker
{
public:
CBaseItemTracker();
void IncrementCount() { ++count; }
protected:
int count;
};
class CDerivedItemTracker : CBaseItemTracker
{
public:
CDerivedItemTracker();
void Print() { printf("something:%d\ncount:%d\n", something, count); }
private:
int something;
};
class CBaseClass
{
public:
BaseClass();
private:
CItemTracker item;
};
class CDerivedClass : CBaseClass
{
public:
CDerivedClass();
CDerivedItemTracker GetDerivedItem();
private:
CDerivedItemTracker derived_item;
};
What I would like to accomplish is that CBaseClass::item and CDerivedClass::derived_item are actually the same object such that:
Code within CBaseClass can update item
Code within CDerivedClass can update derived_item (and therby also update item)
Code external to CDerivedClass can retrieve a CDerivedItemTracker object that includes the item variable.
I feel like I am trying to do something that is fundamentally wrong but I'm not seeing a good way to resolve it.
Your goal is that code within CBaseClass can update base member item and
code within CDerivedClass can update members derived_item as well as item.
Is it a member access problem ?
The first two constraints are the basics of inhertance.
The only problem in your code is that you have item member as private. This means that the derived classes won't have access to it. Just change it to be protected instead:
class CBaseClass
{
public:
BaseClass();
protected: //<===== derived classes will have direct acess to this member
CItemTracker item;
};
class CDerivedClass : CBaseClass
{
public:
CDerivedClass();
CDerivedItemTracker GetDerivedItem();
private: // you can leave it private, but if further dirved classe need access
// make it protected as well, but then you should consider public inheritance
// so that the further derived also see the item.
CDerivedItemTracker derived_item;
};
Now the derived class sees both itmes. In GetDerivedItem() you can choose which item to return. But item and derived_item will remain unrelated, as your class definitions define two distinct members.
Or is it about sharing a single (derived) item ?
The third requirement makes the things a little bit more complex. I'm not 100% sure of your intentions. But if the intention is to extend in a derived class an item of the base class, this wont be possible as such, due to C++ standard constraints on the object layout.
Fortunately there are two main alternatives: templates or dynamic member.
Template approach
The template approach should be considered if at compile time you do already make the choice of the member type.
template <class myitem>
class CBase
{
public:
CBase() {}
protected:
myitem item;
};
template <class myitem>
class CDerived : CBase<myitem>
{
public:
CDerived() {}
myitem GetDerivedItem() { return item; }
};
You can use this as follows:
CBase<CBaseItem> b;
CDerived<CDerivedItem> d;
d.GetDerivedItem().Print();
The principle is that for object d in CBase would have a CDerivedItem item, even if you would only access to the subset of its public CBaseItem members.
Dynamic approach
The dynamic approach doesn't use templates, but creates the item during the construction.
Here I present a simple implementation based on references, taking the luxury of some unused members. A more space efficient pointer based variant with dynamic allocation of the item should be prefered whenever space is critical.
class CBase
{
public:
CBase() : item(base_item) {} // when lonesome object: uses its own item
protected:
CBase(CBaseItem &itm) : item(itm) {} // when subovject of a derived class
CBaseItem &item;
private:
CBaseItem base_item; // used only for non derived CBase object.
};
class CDerived : CBase
{
public:
CDerived() : CBase(derived_item) {} // Tell the base class that there's already an item to be used.
CDerivedItem GetDerivedItem() { return derived_item; }
// we can use item as well: it'll be the CBaseItem subobject of derived_item
private:
CDerivedItem derived_item;
};
ATTENTION: for this to work you need public inhertance between item classes ( class CDerivedItem : public CBaseItem)
The difficulty here, is that base classes are constructed first. So you have to provide to the base class constructor the item reference that it has to use. If inadvertently you'd forget, the base would think it is a free object and will use a separate item. THis is why I'd suggest to use the template approach if possible.