简体   繁体   中英

c++ how to implement const static members in derived classes

In C++, I have several classes inheriting from an abstract super class. Subclasses have a static attribute sharing the same name type but of course have different values. My question is what is the best approach to implement this and what are the pros and cons for each implementation.

PS: There are some related discussions like here but most don't explain why approach (which works on my machine) 1 below should not be used. Besides, the subclass methods in approach 2 are not static and wwe will have to get an instance to invoke them.

Apporach 1: uinitialized const static in superclass

class Abstract {
  public:
    const static int type;
};

class C1: public Abstract {
  public:
    const static int type = 1;
};

class C2 : public Abstract {
  public:
    const static int type = 2;
};

Approach 2: using virtual functions instead of variables

class Abstract {
  public:
    virtual int get_type() = 0;
};

class C1: public Abstract {
  public:
    int get_type() {return 1;}
};

class C2 : public Abstract {
  public:
    int get_type() {return 2;}
};

Other approaches that I'm not aware of...

EDIT:

As some answers/comments mentioned below, I'm trying to identify actual type at runtime. However I cannot really think of a nicer design.

To make it concrete, let's say Abstract=EduInst for educational institution, C1=Univ , C2=College , etc. I have a std::map<Key, EduInst*> storing all institutions, which are generated at runtime depending on user input. At times I need to operate only on Univ s or College s. What is a good way to implement this?

First the warnings:

Inheritance describes an "is kind of" relationship with the base class. It only makes sense when you are storing different kinds of objects in the same container, when those kinds of object absolutely share the same interface, and when no special handling is required on any one of the derived classes (ie when you, the object's consumer don't need to know its type).

Furthermore, if you only have a few kinds of the same thing, and those kinds of thing can possibly be known at compile time, then it's probably a mistake to use inheritance.

If your inherited object must identify its actual type to a client, this is further evidence that inheritance is the wrong solution - since now you're going to use code to find code, which is a bad idea (it's not testable, and it's liable to go wrong when your program is in a state that you didn't anticipate).

Furthermore, if you have objects that are dissimilar but need to be stored in the same container, then boost::variant is probably the solution you're looking for. You would then use boost::static_visitor to perform operations on the object in the variant. The advantage of this is that is absolutely type-safe and the compiler won't allow you to forget to handle a type.

Having said all that...

approach 1 won't work because if you have the type of the derived class already, you'll always get the base class' type.

approach 2 will work but it's horrid and an indication of a broken design.

You can't have "virtual" static members.

Approach one is for finding out the "type" attribute of a class, the second for finding out the "type" attribute of an instance.
To put it differently: to use the first, you need to know the class; to use the second, you need to know the instance.
It's impossible to write code where you know neither.

Note that approach one can give you unexpected results if you use type inside a function in a base class.
For instance,

class Abstract
{
public:
    int get_type() const { return type; }
};

// ...
C1 c;
std::cout << c.get_type(); 

will output 0, since that is the value of Abstract::type .

A variation of the second approach lets you avoid the virtual function if you sacrifice the space of another member:

class Abstract {
  public:
    // ...
    int get_type() const { return type; }
  protected:
    Abstract(int t) : type(t) {}
  private:
    int type;
};

class C1: public Abstract {
  public:
    C1() : Abstract(1) {}
};

class C2 : public Abstract {
  public:
    C2() : Abstract(2) {}
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM