2015-12-07 3 views
0

В C++ у меня есть несколько классов, наследующих от абстрактного суперкласса. Подклассы имеют статический атрибут, имеющий одно и то же имя type, но, разумеется, имеют разные значения. Мой вопрос заключается в том, что является наилучшим подходом к реализации этого и каковы плюсы и минусы для каждой реализации.C++ как реализовать константные статические члены в производных классах

PS: Существует несколько связанных дискуссий, таких как here, но большинство из них не объясняют, почему подход (который работает на моей машине) 1 ниже не должен использоваться. Кроме того, методы подкласса в подходе 2 не являются статическими, и нам придется получить экземпляр для их вызова.

Apporach 1: uinitialized const static в суперкласса

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; 
}; 

подход 2: использование виртуальных функций вместо переменных

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;} 
}; 

Другие подходы, которые я не в курсе ...

EDIT:

Как некоторые ответы/комментарии, упомянутые ниже, я пытаюсь определить фактический тип во время выполнения. Однако я не могу думать о более приятном дизайне.

Чтобы сделать бетон, скажем Abstract=EduInst для образовательного учреждения, C1=Univ, C2=College и т.д. У меня есть std::map<Key, EduInst*> хранящих все институты, которые создаются во время выполнения в зависимости от пользовательского ввода. Иногда мне нужно работать только на Univ с или College с. Что это хороший способ реализовать это?

+3

В первых, у вас есть три разных, совершенно не связанные переменные. – molbdnilo

+0

Но в подходах подхода2 в подклассе не статичны, поэтому у меня должен быть экземпляр для их вызова. – wlnirvana

+2

Что вы пытаетесь сделать? 'switch' в динамическом типе переменной? – TartanLlama

ответ

1

У вас не может быть «виртуальных» статических элементов.

Подход к поиску атрибута «type» для класса, второй для определения атрибута «type» экземпляра.
По-разному: чтобы использовать первый, вам нужно знать класс; чтобы использовать второй, вам нужно знать экземпляр.
Невозможно написать код, в котором вы не знаете.

Обратите внимание, что подход может дать неожиданные результаты, если вы используете type внутри функции в базовом классе.
Например,

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

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

будет выводить 0, так что значение Abstract::type.

Разновидностью второго подхода позволяет избежать виртуальной функции, если вы жертвуете пространство другого члена:

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) {} 
}; 
2

Первые предупреждения:

Наследование описывает «является своего рода» отношений с базовым классом. Это имеет смысл только при хранении различных объектов в одном и том же контейнере, когда эти объекты абсолютно разделяют один и тот же интерфейс и когда никакой специальной обработки не требуется ни на одном из производных классов (т. Е. Когда вы, потребитель объекта не необходимо, чтобы узнать его тип).

Кроме того, если у вас есть только несколько видов одной и той же вещи, и такие вещи могут быть известны во время компиляции, то, вероятно, ошибочно использовать наследование.

Если ваш наследуемый объект должен идентифицировать свой фактический тип для клиента, это еще одно доказательство того, что наследование является неправильным решением - поскольку теперь вы собираетесь использовать код для поиска кода, что является плохой идеей (это невозможно проверить , и он может ошибаться, когда ваша программа находится в состоянии, которое вы не ожидали).

Кроме того, если у вас есть объекты, которые отличаются друг от друга, но их нужно хранить в одном контейнере, то boost::variant, вероятно, является решением, которое вы ищете. Затем вы должны использовать boost::static_visitor для выполнения операций над объектом в варианте. Преимущество этого заключается в том, что он абсолютно безопасен по типу, и компилятор не позволит вам забыть обращаться с типом.

Сказав все это ...

Подход 1 не будет работать, потому что если у вас уже есть тип производного класса, вы всегда будете получать тип базового класса.

подход 2 будет работать, но это ужасно и указывает на сломанный дизайн.

+0

См. Править выше. Оказывается, мои объекты похожи, поэтому я хочу сохранить их в одном контейнере. Однако мне все равно нужно использовать код для поиска кода, если я не буду хранить 'type' явно или использовать что-то вроде' isinstanceof'. – wlnirvana

+0

После вашего редактирования я более убежден, чем раньше, что виртуальное наследование - неправильное решение. Однако, если вы должны проверить тип объекта, используйте typeid(). –

+0

Что может быть лучшим дизайном для этой проблемы? 'Univ',' College' имеют много общего, например 'enroll()', 'tuition' и т. Д. – wlnirvana