views:

2203

answers:

10

Is there anyway to have a sort of virtual static member in C++?

For example:

class BaseClass {
    public:
        BaseClass(const string& name) : _name(name) {}
        string GetName() const { return _name; }
        virtual void UseClass() = 0;
    private:
        const string _name;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass("DerivedClass") {}
        virtual void UseClass() { /* do something */ }
};

I know this example is trivial, but if I have a vector of complex data that is going to be always the same for all derived class but is needed to be accessed from base class methods?

class BaseClass {
    public:
        BaseClass() {}
        virtual string GetName() const = 0;
        virtual void UseClass() = 0;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() {}
        virtual string GetName() const { return _name; }
        virtual void UseClass() { /* do something */ }
    private:
        static const string _name;
};

string DerivedClass::_name = "DerivedClass";

This solution does not satify me because I need reimplement the member _name and its accessor GetName() in every class. In my case I have several members that follows _name behavior and tenths of derived classes.

Any idea?

A: 

Could you describe your design and your problem in more detail please?

In your description of the design, please include information as to your end-goal. (e.g. A base class and derived class such as the base class will store objects that can be modified by the parent and child classes without knowing about child classes)

As your question stands, it seems like you're fighting against the language. Perhaps there is another way to approach the problem that would get you what you want?

Misha M
+1  A: 

It seems like the answer is in the question - the method you suggested seems to be the right direction to go, except that if you have a big number of those shared members you might want to gather them into a struct or class and past that as the argument to the constructor of the base class.

If you insist on having the "shared" members implemented as static members of the derived class, you might be able to auto-generate the code of the derived classes. XSLT is a great tool for auto-generating simple classes.

In general, the example doesn't show a need for "virtual static" members, because for purposes like these you don't actually need inheritance - instead you should use the base class and have it accept the appropriate values in the constructor - maybe creating a single instance of the arguments for each "sub-type" and passing a pointer to it to avoid duplication of the shared data. Another similar approach is to use templates and pass as the template argument a class that provides all the relevant values (this is commonly referred to as the "Policy" pattern).

To conclude - for the purpose of the original example, there is no need for such "virtual static" members. If you still think they are needed for the code you are writing, please try to elaborate and add more context.

Example of what I described above:

class BaseClass {
    public:
        BaseClass(const Descriptor& desc) : _desc(desc) {}
        string GetName() const { return _desc.name; }
        int GetId() const { return _desc.Id; }
        X GetX() connst { return _desc.X; }
        virtual void UseClass() = 0;
    private:
        const Descriptor _desc;
};


class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(Descriptor("abc", 1,...)) {}
        virtual void UseClass() { /* do something */ }
};

class DerDerClass : public BaseClass {
    public:
        DerivedClass() : BaseClass("Wowzer", 843,...) {}
        virtual void UseClass() { /* do something */ }
};

I'd like to elaborate on this solution, and maybe give a solution to the de-initialization problem:

With a small change, you can implement the design described above without necessarily create a new instance of the "descriptor" for each instance of a derived class.

You can create a singleton object, DescriptorMap, that will hold the single instance of each descriptor, and use it when constructing the derived objects like so:

enum InstanceType {
    Yellow,
    Big,
    BananaHammoc
}

class DescriptorsMap{
    public:
        static Descriptor* GetDescriptor(InstanceType type) {
            if ( _instance.Get() == null) {
                _instance.reset(new DescriptorsMap());
            }
            return _instance.Get()-> _descriptors[type];
        }
    private:
        DescriptorsMap() {
            descriptors[Yellow] = new Descriptor("Yellow", 42, ...);
            descriptors[Big] = new Descriptor("InJapan", 17, ...)
            ...
        }

        ~DescriptorsMap() {
            /*Delete all the descriptors from the map*/
        }

        static autoptr<DescriptorsMap> _instance;
        map<InstanceType, Descriptor*> _descriptors;
}

Now we can do this:

class DerivedClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.BananaHammoc)) {}
        virtual void UseClass() { /* do something */ }
};

class DerDerClass : public BaseClass {
    public:
        DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.Yellow)) {}
        virtual void UseClass() { /* do something */ }
};

At the end of execution, when the C runtime performs uninitializations, it also calls the destructor of static objects, including our autoptr, which in deletes our instance of the DescriptorsMap.

So now we have a single instance of each descriptor that is also being deleted at the end of execution.

Note that if the only purpose of the derived class is to supply the relevant "descriptor" data (i.e. as opposed to implementing virtual functions) then you should make do with making the base class non-abstract, and just creating an instance with the appropriate descriptor each time.

Hershi
A: 

I'm not sure about what you're trying to do. This quote doesn't really mesh with what you wrote for examples.

I know this example is trivial, but if I have a vector of complex data that is going to be always the same for all derived class but is needed to be accessed from base class methods?

Can you put that vector of complex data in your base class and make it static?

Baltimark
A: 

Baltimark:

I know this example is trivial, but if I have a vector of complex data that is going to be always the same for all derived class but is needed to be accessed from base class methods?

Can you put that vector of complex data in your base class and make it static?

No, because it will be different for each derived class, but it will be shared by all instances of the derived classes.

martjno
+1  A: 
Pat Notz
A: 

Hershi: your example is reasonable but at the end you are creating a new instance of "Descriptor" every time a new object is instantiated.

Shog9: your solution will work for string, but for any other type I'm going to implement this way there will be an object creation every time the method is called.

Misha M: yes, I'm probably fighting the language. But my purpose I think it's pretty simple: I want all derived classes share some data data that is const static (since it's a distinctive feature of the class type, not the object instance), but I want it to be accessible directly by the base class, since it will be a kind of data that all classes should implement (but, of course in a different manner by every class).

martjno
+1  A: 
Misha M
A: 

@Pat Notz: i think your solution is the best... the only question is how and when to call delete on the static data member...

martjno
+5  A: 

Here is one solution:

struct BaseData
{
  const string my_word;
  const int my_number;
};

class Base
{
public:
    Base(const BaseData* apBaseData)
    {
        mpBaseData = apBaseData;
    }
    const string getMyWord()
    {
        return mpBaseData->my_word;
    }
    int getMyNumber()
    {
        return mpBaseData->my_number;
    }
private:
    const BaseData* mpBaseData;
};

class Derived : public Base
{
public:
    Derived() : Base(&sBaseData)
    {
    }
private:
    static BaseData sBaseData;
}

BaseData Derived::BaseData = { "Foo", 42 };
Jeremy
A: 

It sounds as if you're trying to avoid having to duplicate the code at the leaf classes, so why not just derive an intermediate base class from the base class. this intermediate class can hold the static data, and have all your leaf classes derive from the intermediate base class. This presupposes that one static piece of data held over all the derived classes is desired, which seems so from your example.

no-op