Reputation: 502
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:
CBaseClass
can update item
CDerivedClass
can update derived_item
(and therby also update item
)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.
Upvotes: 1
Views: 173
Reputation: 73386
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
.
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.
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.
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.
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.
Upvotes: 2