Suppose we have the following template class, inspired by std::shared_ptr (ignore bad memory management for simplicity):
template <class C> class shared_class {
public:
const shared_class& operator=(const shared_class& rhs) {
ptr = rhs.ptr;
refs[ptr] += 1;
return *this;
}
C* data() { return ptr; }
protected:
shared_class() {
if (ptr == nullptr)
ptr = new C;
refs[ptr] = 1;
}
shared_class(const shared_class& other) {
ptr = other.ptr;
refs[ptr] += 1;
}
~shared_class() {
if ((refs[ptr] -= 1) == 0) {
refs.erase(ptr);
delete ptr;
}
}
private:
static std::unordered_map<C*, size_t> refs;
C* ptr = nullptr;
};
template <class C> std::unordered_map<C*, size_t> shared_class<C>::refs = {};
I would like to use it in the following way:
class A_data {
protected:
int foo = 50;
friend class A;
friend class shared_class<A_data>;
};
class A : protected shared_class<A_data> {
public:
void foo(int f) { data()->foo = h; }
int foo() { return data()->foo; }
};
using namespace std;
int main(){
A a;
A b = a;
a.foo(40);
cout << b.foo(); // 40
}
This works well, but now suppose I want to create a class that inherits A, but also inherits its data, such as this:
class B_data : public A_data {
int bar = 100;
friend class B;
friend class shared_class<B_data> // Probably wrong
};
class B : public A {
int bar() {
return data()->bar(); // Error: no member 'bar' in A_data
}
}
This is a problem, because the constructor in shared_class only knows how to allocate A_data. It seems to me that I am only able to decide on one form of inheritence: either I inherit the template class like above, or I can inherit a different shared_class template, like this:
class B_data : public A_data {
int bar = 100;
friend class B;
friend class shared_class<B_data> // Now it's not wrong
};
class B : public shared_class<B_data> {
int bar() {
return data()->bar(); // Now it will work
}
}
While this works, I lose relation to the A class, and am now unable to do use A::foo, forcing me to define it in B:
class B : public shared_class<B_data> {
void foo(int f) { data()->foo = h; }
int foo() { return data()->foo; }
int bar() { return data()->bar(); }
}
Is there a (relatively elegant) way to make this work as though B inherits A while simultaneously B_data inherits A_data?