C ++创建一个通用接口

C++ Make a generic interface

我有一个接口(这里缺少很多成员,但是请注意这个接口是强制的)。我需要5个继承自它的类,它们将具有一个值属性。所以,INS实现5个类(char、short、int、float、double)的tead,我想到了一个模板类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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; }
};

…这样就可以工作了:

1
2
3
4
5
6
7
8
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,因为它是我需要的最大大小的类型。但是,我不喜欢那个解决方案。


如果您的接口上只有一个方法(getValue()),那么您只需要模板类实现。

但是,如果您想要这样的接口:

1
2
3
std::string getValue();
int getValue();
long getValue();

那么您就走运了,因为您不能只根据返回类型重载函数名。或者,您可以创建包装类型。

编辑

我的意思是,如果需要GetValue返回多个类型,您可以通过多种方式使用封装所需功能的包装类,而不是将其添加到顶级接口。它可能看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
}

那么你的界面是

1
2
3
public class my_interface{
  virtual Wrapper getVal();
}

您在这里的收获并不多,因为用户仍然需要调用包装器的正确子成员。如果需要,还可以将返回值表示为字符串。

请注意,使用工会时,您需要注意以下注意事项:http://en.cppreference.com/w/cpp/language/union

编辑2:你可以用模板化的返回来做这个。

1
2
template<typename = T>
const T& getVal(const T& typeToAllowMethodOverriding) const;


我认为你最好的办法是使用/实现类似于boost::variant的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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; }
};

然后可以实现算术运算符:

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

您还可以将boost::variant包装在另一个类中,以提供到基本类型的转换运算符。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    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; }
    };

它适用于所有类型,但对于字符串类型,必须对模板进行专门化。


您也可以将类"我的接口"设置为模板类:

1
2
3
4
5
6
template<typename T>
class my_interface
{
public:
    virtual T getValue() const = 0;
};

这将为您使用的每个T类型生成一个接口和一个类。


记住,"virtual…"的意思是"在类中创建一个函数指针,我将使用它来调用正确的派生类"。它只是一个指针——所以在调用它之前,必须在返回类型上达成一致。C++没有其他语言的动态类型和反射——它必须知道在调用之前返回类型是什么。