I have this optimization problem where my program goes through a configuration phase then an execution phase. During configuration, an implementation of a function is selected, then this function is called at each loop iteration during execution.
I want to avoid going through switch/case at each loop to check which function to call. Solution is a function pointer. Now each of these function can have an internal state. A good solution would be inheritance where each class implements the "do_something()" function of the base class and the compiler makes a vtable and everything is fine.
Now, I also want to optimize memory usage. Since I always use one implementation at the time, the internal state of each instance can share the same memory space. This becomes a problem as I can't put inherited instances into a union; compiler is not happy about it (it make sense I guess, because of the vtable probably).
The best solution I found to that problem is to declare a structure of data that uses a union outside of the classes and pass a pointer to it to each instance of the class.
Is there a better way to do?
EDIT : In this case, no dynamic allocation is to be used.
See code below:
The problem
#include <stdio.h>
using namespace std;
class Base{
public:
virtual void doprint() = 0;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d",foo);
};
int foo;
};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", bar);
};
unsigned int bar;
};
int main()
{
// Changing this for a struct works
union{
ChildA a;
ChildB b;
} u;
// Configure phase
u.a.foo = -10;
Base *pbase = &u.a;
// Exec phase
pbase->doprint();
return 0;
}
The above code make the compiler say:
error: union member ‘main()::::a’ with non-trivial ‘ChildA::ChildA()’
The ugly solution
#include <stdio.h>
using namespace std;
union InternalData{
struct {
int foo;
} data_for_a;
struct {
unsigned int bar;
} data_for_b;
};
class Base{
public:
void init(InternalData *data)
{
m_data = data;
}
virtual void doprint() = 0;
protected:
InternalData* m_data;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d", m_data->data_for_a.foo);
};
};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", m_data->data_for_b.bar);
};
};
int main()
{
ChildA a;
ChildB b;
InternalData internal_data;
// Configure phase
internal_data.data_for_a.foo = -10;
a.init(&internal_data);
Base *pbase = &a;
// Exec phase
pbase->doprint();
return 0;
}
You don't really want a union (nobody ever really wants a union...)
What you really want is a place to place your implementations into, and to get an interface pointer out, and a guarantee that it's properly destroyed afterwards.
std::variant< ChildA, ChildB> impl; //define buffer that correctly destroys
Base *pbase; //declare the Base pointer.
impl = ChildA{}; //assign it an implementation
pbase = std::get<ChildA>(impl); //assign pointer to that implementation
If you C++ doesn't have std::variant, then you can implement the key pieces for a destructing buffer yourself. A minimal version looks something like this:
template<class Base, std::size_t size, std::size_t align>
class buffer {
static_assert(std::has_virtual_destructor_v<Base>);
std::aligned_storage_t<size, align> rawbuffer;
Base* pbase=0;
public:
~buffer() {if (pbase) pbase->~Base();};
Base* get() {return pbase;}
template<class T, class...Us>
Base* construct(Us&&...vs) {
static_assert(sizeof(T) <= sizeof(rawbuffer));
assert(pbase == nullptr);
pbase = new(reinterpret_cast<T*>(&rawbuffer)) T(std::forward<Us>(vs)...);
return pbase;
}
};
Note that you'll almost certainly want your Base to have a virtual destructor.
https://coliru.stacked-crooked.com/a/4d08c8b3b9625988
Related
pimpl.h
#include <memory>
class MyClassImpl;
class MyClass {
void Foo();
struct MyStruct {
int a;
int b;
} variable_struct;
private:
std::unique_ptr<MyClassImpl> m_pImpl;
};
pimpl.cpp
class MyClassImpl
{
public:
void DoStuff() { /*...*/ }
struct MyStructImpl {
int a;
int b;
} variable_struct_impl;
};
// MyClass (External/User interface)
MyClass::MyClass () : m_pImpl(new MyClassImpl()) { }
MyClass::~MyClass () = default;
void MyClass::Foo() {
m_pImpl->DoStuff();
}
How/What's the best practice to share a public member of the implementation to the Pimpl class (end user)?
What if they have a different name like in my example with struct MyStruct and struct MyStructImpl (variable_struct / variable_struct_impl)?
For methods, that's quite clear, we need to make the forward method anyway. (Foo() forwarded to DoStuff() in the example)
How to give access to public members with Pimpl?
You don't. The point of PIMPL is to hide all members of the Private IMPLementation, and having public access to them is entirely contrary to that point.
If you want pubic access, then don't put the member in a PIMPL.
I have an abstract base class IThingDoer, with a virtual method doThingWithData. What I want is to have concrete classes of IThingDoer implement doThingWithData(&someType dat), except that the variable type of dat (i.e. what someType is) varies between different concrete classes.
For example:
class IThingDoer {
public:
virtual void doThingWithData(&someType dat); //??
};
struct Foo {
int foo1;
double foo2;
};
class FooThingDoer : public IThingDoer {
public:
void doThingWithData(&Foo dat){
std::cout << dat.foo1
}
};
struct Bar {
float bar1[2];
};
class BarThingDoer : public IThingDoer {
public:
void doThingWithData(&Bar dat){
std::cout << (dat.bar1[0] + dat.bar1[1]);
}
};
I've tried having Foo and Bar both inherit from another base data class: (I've changed what actually happens to simplify the example a bit)
class BaseData{
public:
int baseData = 1;
};
class IThingDoer{
public:
virtual void doThingWithData(BaseData dat) = 0;
};
class FooData : public BaseData {
public:
int otherData = 5;
};
class FooThingDoer : public IThingDoer {
public:
void doThingWithData(BaseData dat){
std::cout << dat.otherData;
}
};
int main()
{
FooThingDoer a = FooThingDoer();
FooData dat = FooData();
a.doThingWithData(dat);
return 0;
}
However, this doesn't work - the compiler can't find dat.otherData since there is no otherData in the BaseData type. Changing BaseData to FooData in FooThingDoer.doThingWithData doesn't work either, since that just causes it to overload the name and not actually implement the virtual function in IThingDoer.
I also looked at templates, but (from the point of view of a relatively inexperienced programmer) it looks like templates are used mostly just to reduce the need for overloading functions for every different possible type.
To be clear, the unknown datatypes are only unknown to the abstract class; they would be known at compile-time.
Is there a way to solve this problem?
Appendix: I might be dealing with an XY problem; for this reason I'm putting some additional context here.
In the bigger picture, this code is going to run on different pieces of hardware, with different sensors and things that it needs to control. The different ThingDoers implement the specific functionality that needs to happen, but in all cases every ThingDoer can be treated as a black box that takes some data structure as input, and performs some actions as output, with the specific input data structure varying between different ThingDoers.
As I understand it, to improve code reuse etc. in the rest of the program, each ThingDoer should inherit from an abstract class that describes this black box functionality, and the rest of the code should work with this interface. I plan on having separate objects prepare the actual data structure that ThingDoer takes as input; again I would have one preparer object per hardware type.
Then, depending on which piece of hardware I'm compiling for, I would include different header files (containing the specific ThingDoer etc. I need) in the compilation. Since at compile time there's a specific ThingDoer and corresponding input preparer that gets used, I figured that the types would be known at compile time so there isn't any dynamic typing.
You can use template for static polymorphism.
#include <iostream>
template <class T>
class IThingDoer {
public:
virtual void doThingWithData(T dat) = 0;
};
struct Foo {
int foo1;
double foo2;
};
class FooThingDoer : public IThingDoer<Foo> {
public:
void doThingWithData(Foo dat) {
std::cout << dat.foo1;
}
};
struct Bar {
float bar1[2];
};
class BarThingDoer : public IThingDoer<Bar> {
public:
void doThingWithData(Bar dat) {
std::cout << (dat.bar1[0] + dat.bar1[1]);
}
};
int main()
{
FooThingDoer a = FooThingDoer();
Foo foo;
foo.foo1 = 5;
foo.foo2 = 5.5;
a.doThingWithData(foo);
return 0;
}
But you example can used too (u can cast only address, not static object):
#include <iostream>
class BaseData {
public:
int baseData = 1;
};
class IThingDoer {
public:
virtual void doThingWithData(BaseData& dat) = 0;
};
class FooData : public BaseData {
public:
int otherData = 5;
};
class FooThingDoer : public IThingDoer {
public:
void doThingWithData(BaseData& dat) {
std::cout << ((FooData&) dat).otherData;
}
};
int main()
{
FooThingDoer a = FooThingDoer();
FooData dat = FooData();
a.doThingWithData(dat);
return 0;
}
After profiling, I found that a large portion of memory of my program are wasted by multi-virtual-inheritance.
This is MCVE to demostrate the problem ( http://coliru.stacked-crooked.com/a/0509965bea19f8d9 )
#include<iostream>
class Base{
public: int id=0;
};
class B : public virtual Base{
public: int fieldB=0;
public: void bFunction(){
//do something about "fieldB"
}
};
class C : public virtual B{
public: int fieldC=0;
public: void cFunction(){
//do something about "fieldC"
}
};
class D : public virtual B{
public: int fieldD=0;
};
class E : public virtual C, public virtual D{};
int main (){
std::cout<<"Base="<<sizeof(Base)<<std::endl; //4
std::cout<<"B="<<sizeof(B)<<std::endl; //16
std::cout<<"C="<<sizeof(C)<<std::endl; //32
std::cout<<"D="<<sizeof(D)<<std::endl; //32
std::cout<<"E="<<sizeof(E)<<std::endl; //56
}
I hope sizeof(E) to be not much more than 16 bytes (id+fieldB+fieldC+fieldD).
From experiment, if it is non virtual inheritance, E's size will be 24 (MCVE).
How to reduce size of E (by C++ magic, change program architecture, or design pattern)?
Requirement:-
Base,B,C,D,E can't be template class. It will cause circular dependency for me.
I must be able to call base class's function from derived class (if any) e.g. e->bFunction() and e->cFunction(), as usual.
However, it is OK if I can't call e->bField anymore.
I still want the ease of declaration.
Currently, I can declare "E inherit from C and D" as class E : public virtual C, public virtual D easily.
I am thinking about CRTP e.g. class E: public SomeTool<E,C,D>{}, but not sure how to make it works.
To make things easier :
In my case, every class is used like it is monolith, i.e. I will never cast object between types like static_cast<C*>(E*) or vise versa.
Macro is allowed, but discouraged.
Pimpl idiom is allowed. Actually, below is what I daydream.
Perhaps, I may be able to remove all virtual-inheritance.
However, with all the requirements, I can't find a way to code it.
In pimpl, if I make E virtual inherit from C & D, etc, all above requirement will be met, but I will still waste a lot of memory. :-
I am using C++17.
Edit
Here is a more correct description of my real-life problem.
I create a game that has many components e.g. B C D E.
All of them are created via pool. Thus, it enables fast iterating.
Currently, if I query every E from a game engine, I will be able to call e->bFunction().
In my most severe case, I waste 104 bytes per object in E-like class. (real hierarchy is more complex)
Edit 3
Let me try again. Here is a more meaningful class diagram.
I have a central system to assign hpPtr,flyPtr,entityId,componentId,typeId automatically already.
i.e. Don't worry how they are initialized.
In real case, dread diamond happen in many classes, this is the most simple case.
Currently, I call like :-
auto hps = getAllComponent<HpOO>();
for(auto ele: hps){ ele->damage(); }
auto birds = getAllComponent<BirdOO>();
for(auto ele: birds ){
if(ele->someFunction()){
ele->suicidalFly();
//.... some heavy AI algorithm, etc
}
}
With this approach, I can enjoy cache coherence as in Entity Component System, and the cool ctrl+space intellisense of HpOO,FlyableOO and BirdOO like in Object-Oriented style.
Everything works fine - it just uses too much memory.
EDIT: based on latest update to the question and some chatting
Here's the most compact maintaining the virtual in all your classes.
#include <iostream>
#include <vector>
using namespace std;
struct BaseFields {
int entityId{};
int16_t componentId{};
int8_t typeId{};
int16_t hpIdx;
int16_t flyPowerIdx;
};
vector<int> hp; // this will contain all the hit points, dynamically resizable, logic up to you
vector<float> flyPower; // this will contain all the fly powers, dynamically resizable, logic up to you
class BaseComponent {
public: // or protected
BaseFields data;
};
class HpOO : public virtual BaseComponent {
public:
void damage() {
hp[data.hpIdx] -= 1;
}
};
class FlyableOO : public virtual BaseComponent {
public:
void addFlyPower(float power) {
flyPower[data.hpIdx] += power;
}
};
class BirdOO : public virtual HpOO, public virtual FlyableOO {
public:
void suicidalFly() {
damage();
addFlyPower(5);
}
};
int main (){
std::cout<<"Base="<<sizeof(BaseComponent)<<std::endl; // 12
std::cout<<"C="<<sizeof(HpOO)<<std::endl; // 24
std::cout<<"D="<<sizeof(FlyableOO)<<std::endl; // 24
std::cout<<"E="<<sizeof(BirdOO)<<std::endl; // 32
}
much smaller class size version dropping all the virtual class stuff:
#include <iostream>
#include <vector>
using namespace std;
struct BaseFields {
};
vector<int> hp; // this will contain all the hit points, dynamically resizable, logic up to you
vector<float> flyPower; // this will contain all the fly powers, dynamically resizable, logic up to you
class BaseComponent {
public: // or protected
int entityId{};
int16_t componentId{};
int8_t typeId{};
int16_t hpIdx;
int16_t flyPowerIdx;
protected:
void damage() {
hp[hpIdx] -= 1;
};
void addFlyPower(float power) {
flyPower[hpIdx] += power;
}
void suicidalFly() {
damage();
addFlyPower(5);
};
};
class HpOO : public BaseComponent {
public:
using BaseComponent::damage;
};
class FlyableOO : public BaseComponent {
public:
using BaseComponent::addFlyPower;
};
class BirdOO : public BaseComponent {
public:
using BaseComponent::damage;
using BaseComponent::addFlyPower;
using BaseComponent::suicidalFly;
};
int main (){
std::cout<<"Base="<<sizeof(BaseComponent)<<std::endl; // 12
std::cout<<"C="<<sizeof(HpOO)<<std::endl; // 12
std::cout<<"D="<<sizeof(FlyableOO)<<std::endl; // 12
std::cout<<"E="<<sizeof(BirdOO)<<std::endl; // 12
// accessing example
constexpr int8_t BirdTypeId = 5;
BaseComponent x;
if( x.typeId == BirdTypeId ) {
auto y = reinterpret_cast<BirdOO *>(&x);
y->suicidalFly();
}
}
this example assumes your derived classes do not have overlapping functionalities with diverging effects, if you have those you have to add virtual functions to your base class for an extra overhead of 12 bytes (or 8 if you pack the class).
and quite possibly the smallest version still maintaining the virtuals
#include <iostream>
#include <vector>
using namespace std;
struct BaseFields {
int entityId{};
int16_t componentId{};
int8_t typeId{};
int16_t hpIdx;
int16_t flyPowerIdx;
};
#define PACKED [[gnu::packed]]
vector<int> hp; // this will contain all the hit points, dynamically resizable, logic up to you
vector<float> flyPower; // this will contain all the fly powers, dynamically resizable, logic up to you
vector<BaseFields> baseFields;
class PACKED BaseComponent {
public: // or protected
int16_t baseFieldIdx{};
};
class PACKED HpOO : public virtual BaseComponent {
public:
void damage() {
hp[baseFields[baseFieldIdx].hpIdx] -= 1;
}
};
class PACKED FlyableOO : public virtual BaseComponent {
public:
void addFlyPower(float power) {
flyPower[baseFields[baseFieldIdx].hpIdx] += power;
}
};
class PACKED BirdOO : public virtual HpOO, public virtual FlyableOO {
public:
void suicidalFly() {
damage();
addFlyPower(5);
}
};
int main (){
std::cout<<"Base="<<sizeof(BaseComponent)<<std::endl; // 2
std::cout<<"C="<<sizeof(HpOO)<<std::endl; // 16 or 10
std::cout<<"D="<<sizeof(FlyableOO)<<std::endl; // 16 or 10
std::cout<<"E="<<sizeof(BirdOO)<<std::endl; // 24 or 18
}
the first number is for unpacked structure, second packed
You can also pack the hpIdx and flyPowerIdx into the entityId using the union trick:
union {
int32_t entityId{};
struct {
int16_t hpIdx;
int16_t flyPowerIdx;
};
};
in the above example if not using packing and moving the whole BaseFields structure into the BaseComponent class the sizes remain the same.
END EDIT
Virtual inheritance just adds one pointer size to the class, plus alignment of the pointer (if needed). You can't get around that if you actually need a virtual class.
The question you should be asking yourself is whether you actually need it. Depending on your access methods to this data that might not be the case.
Considering you need virtual inheritance but all common methods that need to be callable from all your classes you can have a virtual base class and use a bit less space than your original design in the following way:
class Base{
public: int id=0;
virtual ~Base();
// virtual void Function();
};
class B : public Base{
public: int fieldB=0;
// void Function() override;
};
class C : public B{
public: int fieldC=0;
};
class D : public B{
public: int fieldD=0;
};
class E : public C, public D{
};
int main (){
std::cout<<"Base="<<sizeof(Base)<<std::endl; //16
std::cout<<"B="<<sizeof(B)<<std::endl; // 16
std::cout<<"C="<<sizeof(C)<<std::endl; // 24
std::cout<<"D="<<sizeof(D)<<std::endl; // 24
std::cout<<"E="<<sizeof(E)<<std::endl; // 48
}
In the case that there are cache misses but the CPU still has power to process the results you can furter decrease the size by using compiler-specific instructions to make the data structure as small as possible (next example works in gcc):
#include<iostream>
class [[gnu::packed]] Base {
public:
int id=0;
virtual ~Base();
virtual void bFunction() { /* do nothing */ };
virtual void cFunction() { /* do nothing */ }
};
class [[gnu::packed]] B : public Base{
public: int fieldB=0;
void bFunction() override { /* implementation */ }
};
class [[gnu::packed]] C : public B{
public: int fieldC=0;
void cFunction() override { /* implementation */ }
};
class [[gnu::packed]] D : public B{
public: int fieldD=0;
};
class [[gnu::packed]] E : public C, public D{
};
int main (){
std::cout<<"Base="<<sizeof(Base)<<std::endl; // 12
std::cout<<"B="<<sizeof(B)<<std::endl; // 16
std::cout<<"C="<<sizeof(C)<<std::endl; // 20
std::cout<<"D="<<sizeof(D)<<std::endl; // 20
std::cout<<"E="<<sizeof(E)<<std::endl; //40
}
saving an additional 8 bytes at the price of possibly some CPU overhead (but if memory is the issue might help).
Additionally if there is really a single function you are calling for each of your classes you should only have that as a single function which you override whenever necessary.
#include<iostream>
class [[gnu::packed]] Base {
public:
virtual ~Base();
virtual void specificFunction() { /* implementation for Base class */ };
int id=0;
};
class [[gnu::packed]] B : public Base{
public:
void specificFunction() override { /* implementation for B class */ }
int fieldB=0;
};
class [[gnu::packed]] C : public B{
public:
void specificFunction() override { /* implementation for C class */ }
int fieldC=0;
};
class [[gnu::packed]] D : public B{
public:
void specificFunction() override { /* implementation for D class */ }
int fieldD=0;
};
class [[gnu::packed]] E : public C, public D{
void specificFunction() override {
// implementation for E class, example:
C::specificFunction();
D::specificFunction();
}
};
This would also allow you to avoid having to figure out what class which object is before calling the appropriate function.
Furthermore, assuming your original virtual class inheritance idea is what works best for your application you could restructure your data so that it's more easily accessible for caching purposes while also decreasing the size of your classes and having your functions accessible at the same time:
#include <iostream>
#include <array>
using namespace std;
struct BaseFields {
int id{0};
};
struct BFields {
int fieldB;
};
struct CFields {
int fieldB;
};
struct DFields {
int fieldB;
};
array<BaseFields, 1024> baseData;
array<BaseFields, 1024> bData;
array<BaseFields, 1024> cData;
array<BaseFields, 1024> dData;
struct indexes {
uint16_t baseIndex; // index where data for Base class is stored in baseData array
uint16_t bIndex; // index where data for B class is stored in bData array
uint16_t cIndex;
uint16_t dIndex;
};
class Base{
indexes data;
};
class B : public virtual Base{
public: void bFunction(){
//do something about "fieldB"
}
};
class C : public virtual B{
public: void cFunction(){
//do something about "fieldC"
}
};
class D : public virtual B{
};
class E : public virtual C, public virtual D{};
int main (){
std::cout<<"Base="<<sizeof(Base)<<std::endl; // 8
std::cout<<"B="<<sizeof(B)<<std::endl; // 16
std::cout<<"C="<<sizeof(C)<<std::endl; // 16
std::cout<<"D="<<sizeof(D)<<std::endl; // 16
std::cout<<"E="<<sizeof(E)<<std::endl; // 24
}
Obviously this is just an example and it assumes you don't have more than 1024 objects at a point, you can increase that number but above 65536 you'd have to use a bigger int to store them, also below 256 you can use uint8_t to store the indexes.
Furthermore if one of the structures above adds very little overhead to it's parent you could reduce the number of arrays you use to store the data, if there's very little difference in the size of objects you can just store all the data in a single structure and have more localized memory accesses. That all depends on your application so I can't give more advice here other than to benchmark what works best for your case.
Have fun and enjoy C++.
You can avoid virtual inheritance by using the following technique: make all classes except leaf classes fully abstract (no data members). All data access is through virtual getters.
class A {
virtual int & a() = 0; // private!
// methods that access a
};
class B : public A {
virtual int & c() = 0; // private!
// methods that access b
};
class C: public A {
virtual int & c() = 0; // private!
// methods that access c
};
class D: public B, public C {
int & a() override { return a_; }
int & b() override { return b_; }
int & c() override { return c_; }
int a_, b_, c_;
};
This way, you can non-vir inherit a class several times without duplicating any data members (because there are none in the first place).
In the example D has A twice, but this is not important since A is virtually empty.
With a typical implementation you should get a vptr per most derived class plus one vptr for each base class except the first at each level in your hierarchy.
Of course you now have a virtual call overhead for each member access, but nothing comes for free.
If this overhead is too much for you, and you still need polymorphism, you will probably need to implement it in a way that doesn't involve the C++ mechanism of virtual functions at all. There are quite a few ways of doing so but of course each comes with its own special drawbacks so it is hard to recommend one.
Consider the following code:
#include <stdio.h>
#include <iostream>
/// Header-file
class Base {
public:
virtual void do_something() const =0;
int GetAttrib () const {return constattribute_;};
static const int constattribute_;
};
typedef Base* Derived_Ptr; //<< adress derived classes by their base-class ptr; so no templates for Base
class DerivedA : public Base {
// static const int constattribute_; //<< change this static attribute for all DerivedA class instances and their derivatives
void do_something() const {};
};
class DerivedB : public Base {
// static const int constattribute_; //<< change this static attribute for all DerivedB class instances and their derivatives
void do_something() const {};
};
/// CC-file
using namespace std;
const int Base::constattribute_(0);
const int DerivedA::constattribute_(1); //<<error: no such variable 'constattribute' in class DerivedA
const int DerivedB::constattribute_(2); //<<error: no such variable 'constattribute' in class DerivedB
int main(void) {
Derived_Ptr derivedA = new DerivedA();
Derived_Ptr derivedB = new DerivedB();
cout << derivedA->GetAttrib() << derivedB->GetAttrib() <<endl;
return 0;
};
The intend being that i have some abstract interface (Base) which defines also a variable, which should be present for all derived classes, and is retrievable. All flavours of subclasses should be forced to/able to redefine their specific value for this variable, at best during class declaration (the values are known at the time the class is declared after all).
I want to achieve code, not altering the main()-program so that the output is '12' and not as of now (uncommenting current lines in the code) '00' (Doing so shadows the fields from base class).
I tried to look into the matter, and there are different paths for solutions, many of which however go contrary to my intuition:
1. Some follow the CRTP pattern, which is however impossible if I want to address my subclasses by their base-ptr in main.
2. Other solutions require to virtualize the 'GetAttrib()' function for every derived instance., which is cumbersome, and action of modifying the attribute is masked within a function definition.
3. A third possibility is to remove the static pattern and have the 'constattribute_' field as a regular member, which however forces me to drag it through all constructors as a parameter.
I am quite sure that there must be some smarter way to do this. Any hints are appreciated.
Using CRTP may get you what you want, assuming you don't have to access GetAttr() through Base* and can leave without constattribute_ in Base itself. Just follow the rule that every programming problem can be solved by entering another level of indirection, which I did below:
class Base {
public:
virtual void do_something() const = 0;
virtual ~Base() // should define it as you are using Base*
{
}
};
typedef Base* Derived_Ptr;
template<class T>
class BaseConstAttr : public Base
{
public:
int GetAttrib () const
{
return(constattribute_);
};
static const int constattribute_;
};
class DerivedA : public BaseConstAttr<DerivedA>
{
public:
void do_something() const
{
};
};
class DerivedB : public BaseConstAttr<DerivedB>
{
public:
void do_something() const
{
};
};
template<> const int BaseConstAttr<DerivedA>::constattribute_(1);
template<> const int BaseConstAttr<DerivedB>::constattribute_(2);
If you need GettAttr from top to bottom of the inheritance tree you can modify the above code a bit, but this will cost you making GetAttr virtual (but still one implementation only):
class Base {
public:
virtual void do_something() const = 0;
virtual int GetAttrib () const = 0;
virtual ~Base() // should define it as you are using Base*
{
}
};
typedef Base* Derived_Ptr;
template<class T>
class BaseConstAttr : public Base
{
public:
int GetAttrib () const
{
return(constattribute_);
};
static const int constattribute_;
};
class DerivedA : public BaseConstAttr<DerivedA>
{
public:
void do_something() const
{
};
};
class DerivedB : public BaseConstAttr<DerivedB>
{
public:
void do_something() const
{
};
};
template<> const int BaseConstAttr<DerivedA>::constattribute_(1);
template<> const int BaseConstAttr<DerivedB>::constattribute_(2);
Please note that I don't know how well (or bad) it will behave with deep inheritance tree (ie. when inheriting from DerivedA and/or DerivedB). In this case I would probably remove BaseConstAttr from inheritance tree right below Base and would try to inject it between most derived class and its predecessor or use multiple inheritance.
What you are requesting requires virtual dispatch somewhere, because you don't know the type of the object you are dealing with until runtime. The purpose of virtual dispatch is to solve exactly the problem you are facing.
The simplest solution is what you have given as number 2: make GetAttrib() virtual, and implement it on each derived class where you introduce a shadowing constattribute_.
static variable in base class is single instance hence it will be reflected same in derived class.
You can make same static member variable in derived class with specific different value you want. Now make getter member function of static variable in Base class as virtual and overload it in derived class which returns is static instance value.
I have update your code to work it, please check ..
#include <iostream>
using namespace std;
class Base {
public:
static const int constattribute_;
virtual void do_something() const =0;
virtual int GetAttrib () const {return constattribute_;};
};
typedef Base* Derived_Ptr; //<< adress derived classes by their base-class ptr; so no templates for Base
class DerivedA : public Base {
static const int constattribute_; //<< change this static attribute for all DerivedA class instances and their derivatives
void do_something() const {};
int GetAttrib () const {return constattribute_;};
};
class DerivedB : public Base {
static const int constattribute_; //<< change this static attribute for all DerivedB class instances and their derivatives
void do_something() const {};
int GetAttrib () const {return constattribute_;};
};
const int Base::constattribute_(0);
const int DerivedA::constattribute_(1); //<<error: no such variable 'constattribute' in class DerivedA
const int DerivedB::constattribute_(2); //<<error: no such variable 'constattribute' in class DerivedB
int main(void) {
Derived_Ptr derivedA = new DerivedA();
Derived_Ptr derivedB = new DerivedB();
cout << derivedA->GetAttrib() << derivedB->GetAttrib() <<endl;
return 0;
};
You should get desired output.
Note : Remember all member variables and func in derived class are private.
I'm facing a problem with a few inherited classes and their base class as well.
For example:
base class{
int x,y; // Doesnt really matter
int counter;
public:
class(int x, int y):x(x), y(y), counter(1){}
void add_counter(){counter++;}
//stuff
virtual ~base(){}
}
class1:public base{
public:
class1():base(1,2){}
}
Every of my inherited classes (which I've a few) they all pass the x,y differently from each other. And then I want this counter to increment when I call it.
The problem I'm facing is that the counter increases ONLY on that iteration. No object is being re-constructed (because I debugged). If I call the add_counter for the class1 it will increase from 1 to 2 but if I call it again it will be the same (1 to 2).
What am I missing here?
Thank you.
What am I missing here?
It seems to me that you want to keep track of the number of objects constructed whose types are derived from Base.
In that case, you need to make counter a static member variable, which will require you to make add_counter a static member function.
However, that will require you to:
Decrement the count in the destructor.
Add a copy constructor in Base to make sure that objects created using a copy constructor are also counted.
Here's a simplified version of base to do that:
class base
{
public:
base() { inrement_counter(); }
base(base const& copy) { inrement_counter(); }
virtual ~base(){ decrement_counter(); }
private:
static int counter;
static void inrement_counter() {++counter;}
static void decrement_counter() {--counter;}
}
int base::counter = 0;
If you want to keep track of the number of derived1 objects constructed, you'll need to add the bookkeeping code to derived1. You can create a class template to streamline that process.
Example:
template <typename T>
struct ObjectCounter
{
ObjectCounter() { inrement_counter(); }
ObjectCounter(ObjectCounter const& copy) { inrement_counter(); }
virtual ~ObjectCounter(){ decrement_counter(); }
static int counter;
static void inrement_counter(){++counter;}
static void decrement_counter(){--counter;}
};
template <typename T>
int ObjectCounter<T>::counter = 0;
class base
{
};
class derived1 : public base, public ObjectCounter<derived1>
{
};
class derived2 : public base, public ObjectCounter<derived2>
{
};
#include <iostream>
int main()
{
derived1 d1;
derived2 d2;
auto d3 = d2;
std::cout << d1.counter << std::endl;
std::cout << d2.counter << std::endl;
}
Output:
1
2