c++ - 使用继承和模板的数据库接口(interface)

标签 c++ templates inheritance

我正在尝试实现一个可以处理不同类型(包括自定义类)的简单数据库接口(interface)。我想选择继承或模板,但似乎我都用了,但效果不佳。

头文件

enum class RECORD_TYPE
{
    TYPE_LONG = 11,
    TYPE_STRING = 12
//other types
};

// the reason I created this class is to use it as function member parent 
class RecordType
{
public:
    RecordType(RECORD_TYPE record_type) : record_type_(record_type) {}
    RECORD_TYPE get_record_type()
    {
        return record_type_;
    }

protected:
    RECORD_TYPE record_type_;
};

template<class T>
class RecordType_t : public RecordType
{
public:
    RecordType_t(T value, RecordType type) : RecordType(type), value_(value) {}
    const T &get_value() const { return value_; }

protected:
    T value_;
};

class RecordType_long : public RecordType_t<long>
{
public:
    RecordType_long(long value) : RecordType_t(value, RECORD_TYPE::TYPE_LONG) {};
};

class RecordType_string : public RecordType_t<std::string>
{
public:
    RecordType_string(std::string value) : RecordType_t(value, RECORD_TYPE::TYPE_STRING) {};
};

用法

void add_record(const RecordType &record)
{   
    //here I need to know the type(string/long/custom) because the types have to be stored different
    switch (record.get_record_type())
    {
    case RECORD_TYPE::TYPE_LONG:
        //long x = record.get_value();

    case RECORD_TYPE::TYPE_STRING:
        //string x = record.get_value();
      //then do something with these values
    };
};

Database db;
RecordType_string str("test");
db.add_record(str);
RecordType_long lng(200);
db.add_record(lng)

我的主要问题(除了我很确定这是糟糕的设计这一事实)是在函数 add() 中我无权访问 get_value() 成员函数,因此我可以获得每种类型的值。因为,当然,在父类中,如果我创建 get_value(),我将不知道要返回什么类型。 你能建议如何更好地实现这个东西吗?

谢谢

附言我可以从 RecordType 动态转换为 RecordType_long/RecordType_string/etc 但我在这里读到这真的是一个非常糟糕的设计。:)

最佳答案

问题在于模板提供了一种与继承提供的行为正交的多态行为。

前者提供parametric polimorphism而后者提供 subtyping .

这两种不同类型的多态性在 C++ 中不会混合在一起。每个模板特化都是不同的类型,与同一模板的其他特化正交,这意味着没有 is-a这些类型之间的关系与继承有关。

所以您的选择实际上取决于您打算使用的设计。例如,为了让每种类型的字段将自身保存在数据库中,您需要让每个实例管理自己的序列化,而无需知道谁是谁,例如:

class SerializableRecord
{
public:
  virtual void save(Database& db) const;
}

class RecordType_long : private RecordType_t<long>, public SerializableRecord
{
public:
  void save(Database& db) const override {
    long value = get_value();
    /* save it on database somehow */
  }
}

这样你就可以同时使用多态和模板但是为了两个不同的目的,而不需要知道你要保存哪种特定的记录,当然这也意味着你需要使用指针或对象切片发生。

另一种解决方案是使 Database::save 模板化并专用于各种类型:

class Database {
  public:
    template<typename T> void save(const T& record);
}

template<> void Database::save<RecordType_t<long>>(const RecordType_t<long>& record) {
  long value = record.get_value();
  // ...
}

实际上你有很多选择,这真的取决于你需要实现什么以及结构本身的复杂性。

关于c++ - 使用继承和模板的数据库接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43016601/

相关文章:

c++ - 什么是对象切片?

类和子类中的 C++ 成员函数指针

c++ - 将 std::unique_ptr 传递给类时出错

c++ - OSX 10.7 上的 clock() 和 CLOCKS_PER_SEC

c++ - 避免在禁用复制的 POD 类型的 memcpy 上出现 `-Wclass-memaccess`

c++ - 非特化模板参数的模板特化

c++ - 模板类中单个方法的模板特化

c++ - 函数调用表达式的类型是什么?

c++ - 使用 ifstream.read(buf, length) 读取文件 - 接收损坏的数据(大多数情况下)

C++:函数指针作为模板参数而不是仿函数