Home > Enterprise >  Overriding static variables when subclassing, with a single accessor in the base class
Overriding static variables when subclassing, with a single accessor in the base class

Time:07-29

I want to have a static member a of a base class B, with the following features:

  1. It is a vector (likely not the "challenging" part).
  2. Derived classes D1, etc., should be able to have similar static members, with different values. Not all the classes would have them, and if a class D2 does not define it, its corresponding a would be the lowest in the parent hierarchy.
  3. I want to access any of these members in any of the classes with a single function getA defined in the base class. E.g., D1 should be able to get its own a (or the lowest in the parent hierarchy, if D1 does not define it).

So far, the solutions I have seen require redefining getA in each derived class in the hierarchy (see below). I want to avoid this for several reasons, e.g., I have a large hierarchy, so applying the required changes, and possible future changes (even if unlikely) become cumbersome.

Are there any alternatives to achieve my goal?

Related:

  1. Overriding static variables when subclassing
  2. https://forums.unrealengine.com/t/workaround-overriding-a-static-variable/91685/2

CodePudding user response:

No, you can't override member variables (static and non-static alike) - only virtual member functions.

the solutions I have seen require redefining getA in each derived class

You would only need to override getA in the classes that should have a separate a.

Example:

struct B {
    virtual std::vector<int>& getA() const { 
        static std::vector<int> a;
        return a; 
    }
};

struct D1 : B {
    std::vector<int>& getA() const override {
        static std::vector<int> a;
        return a; 
    }    
};

struct D2 : B { // no need to override `getA` here - it'll use `B::getA`
};

Demo

CodePudding user response:

How about having a simple (non-static) virtual getter and the static var in that getter? As you said, you already have an instance, so you have access to the virtual table. To make it automatic, we might rely on the typical CRTP:

class Base {
public:
    virtual const std::vector<int>& getA() = 0;
};

template<typename B, typename D>
class BaseImpl : public B {
public:
    const std::vector<int>& getA() override { return D::static_var; };
};

class D1 : public BaseImpl<Base, D1>
{
public:
    static const std::vector<int> static_var;
};

const std::vector<int> D1::static_var = {1};

class D2 : public D1 /* no static_var */
{
};

class D3 : public BaseImpl<D2, D3>
{
public:
    static const std::vector<int> static_var;
};

const std::vector<int> D3::static_var = {1, 3};

You might even automate the detection of static_var if that's easier for you (via std::enable_if<> and is_detected<>).

  • Related