2014-02-21 6 views
0

У меня есть интерфейс (там отсутствует много членов, но помните, что этот интерфейс является обязательным). Мне понадобятся 5 унаследованных от него классов, которые будут иметь атрибут . Так, Ins \ TEAD в реализации 5 классов (для полукокса, короткий, INT, поплавка, двойной), я думал о классе шаблона:C++ Сделать общий интерфейс

class my_interface 
{ 
public: 
    virtual [various_types] getValue() const = 0; 
}; 

template<typename T> 
class my_class : public my_interface 
{ 
private: 
    T _value; 
public: 
    my_class(T value) : _value(value) {} // initialize the attribute on construct 
    virtual T  getValue() const { return _value; } 
}; 

... так что-то подобное может работать:

void    my_function() 
{ 
    my_inteface* a = new my_class<char>(42); 
    my_interace* b = new my_class<short>(21); 
    int    result; 

    result = a->getValue() + b->getValue(); 
} 

Но я не понимаю, как я мог это сделать. Кажется, вы не можете сделать шаблоны на интерфейсе чистым виртуальным. Для меня единственным способом, который мог бы работать, было бы сделать getValue(), чтобы всегда возвращать double, так как это самый высокий размер, который мне нужен. Однако мне не нравится это решение.

+0

Возможный дубликат [C++ Virtual template method] (http://stackoverflow.com/questions/7968023/c-virtual-template-method) – MatthiasB

+0

Нужны ли вам все арифметические операции над вашими типами или ограничены? У вас всегда есть проблема, что вы не знаете фактического типа подкласса. – MatthiasB

+0

Ваша проблема в том, что вы не можете иметь такие, как '[different_types]', как тип возврата виртуальной функции вообще, если вы не сделаете также 'my_interface' класс шаблона. –

ответ

0

Помните, что «virtual ...» означает «сделать указатель функции в классе, который я буду использовать для вызова правильного производного класса». Это только указатель - так что вы должны договориться о типе возврата, прежде чем называть его. C++ не имеет динамических типов и отражения других языков - он должен знать, каков тип возврата перед вызовом.

1

Если у вас есть только один метод (getValue()) на вашем интерфейсе, вам нужна только реализация класса шаблона.

Однако, если вы хотите, чтобы интерфейс, как это:

std::string getValue(); 
int getValue(); 
long getValue(); 

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

EDIT

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

enum ValType{ 
    INT, CHAR, STR, DEQUE 
}; 

class Wrapper{ 
private: 
    union S{ 
    int intVal; 
    char charVal; 
    std::string stringVal; 
    std::deque dequeVal; 
    ~S() {} 
    } theVal; 

    ValType heldType; 
public: 
    void setVal(int value){ heldType = INT; theVal.intVal = value; } 
    void setVal(char value){ heldType = CHAR; theVal.charVal = value; } 
    // ... and so on 
    int getIntVal() const { 
    if(heldType!=INT) 
     throw std::runtime_error("Cop on"); 
    return theVal.int; 
    } 
    // and so on 
} 

Тогда вашего интерфейс

public class my_interface{ 
    virtual Wrapper getVal(); 
} 

Вы на самом деле не набираете много здесь, как пользователь будет по-прежнему должен вызвать правильный элемент дочерней обертки. Вы также можете просто представить возвращаемые значения в виде строки, если хотите.

Обратите внимание, что с помощью объединения вы должны быть осторожны с оговорками: http://en.cppreference.com/w/cpp/language/union

EDIT 2: Вы можете сделать это с помощью шаблонного возвращения

template<typename = T> 
const T& getVal(const T& typeToAllowMethodOverriding) const; 
+0

Нет. Я сказал, что в этом интерфейсе есть другие методы. Но что вы подразумеваете под типом обертки? – kirly

+0

О, хорошо, я понимаю, что вы здесь сделали. Но, как вы сказали, получение значений так же сложно, как и для шаблона класса ... На самом деле, я думаю, что хорошая вещь - это что-то вроде возврата шаблонного объекта, который содержит значение. Но у меня такая же проблема: у моего интерфейса не может быть метода, который возвращает шаблонный тип ... – kirly

+0

Да, вы можете вернуть тип шаблона, но только если вы знаете тип при его вызове. Вам все равно необходимо предоставить механизм для правильного переопределения метода (с использованием параметра). См. EDIT 2 – Dennis

0

Вы могли бы сделать класс my_interface класс шаблонов:

template<typename T> 
class my_interface 
{ 
public: 
    virtual T getValue() const = 0; 
}; 

Это создаст интерфейс и класс для каждого используемого вами типа T.

+1

Это работает? my_interface и my_interface были бы разными типами, тем самым устраняя точку интерфейса – MatthiasB

+0

Ну, только если у вас есть несколько подклассов того же типа, но если есть только один подкласс для каждого типа, то это не реально жизнеспособное решение –

0
template<typename U> 
class my_interface 
    { 
    public: 

     virtual U getValue() const = 0; 
    }; 

    template<typename T> 
    class my_class : public my_interface<T> 
    { 
    private: 
     T _value; 
    public: 
     my_class(T value) : _value(value) {} // initialize the attribute on construct 

      T getValue() const { return _value; } 
    }; 

Это работает для всех типов, но для строкового типа вы должны сделать специализацию шаблонов

0

Я думаю, что ваш лучший выстрел будет использовать/реализовать что-то вроде boost::variant.

typedef boost::variant<char, short, int, float, double> Value; 

class my_interface 
{ 
public: 
    virtual Value getValue() const = 0; 
}; 

template<typename T> 
class my_class : public my_interface 
{ 
private: 
    T _value; 
public: 
    my_class(T value) : _value(value) {} // initialize the attribute on construct 
    virtual Value getValue() const { return _value; } 
}; 

Тогда вы могли бы реализовать арифметические операции:

Value operator+(const Value &lhs, const Value &rhs) { 
    //Check the internal types of lhs and rhs and perform the operation 
} 

Вы также можете обернуть boost::variant в другом классе, чтобы обеспечить оператор преобразования для базовых типов.

Смежные вопросы