【问题标题】:How to create user defined type template class object C++如何创建用户定义类型模板类对象C++
【发布时间】:2014-12-21 03:28:20
【问题描述】:

我正在努力让用户选择数据类型模板将被创建为。 由于必须在编译时定义模板类型,我必须指定数据类型模板将使用 eg(string,int, so on),但这意味着我不能在以后更改它,从让我们说 string 到 int 即使我的模板支持它,因为模板类对象被声明为字符串。 我的班级声明如下:

template <class T>
class MyHashTable
{
public:
    string deleted="deleted";
    unsigned short tableSize;
    // array of vectors, hash table container
    vector<T>* myTable;
    vector<T>* deletionTable;

    MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]),  deletionTable(new vector<T>[tableSize])
    {
        this->tableSize=tableSize;
    }

类外的对象声明

    MyHashTable <string>* myChainedTable=NULL ;
    string tableType;

对象初始化

 if (myChainedTable)
{
    delete myChainedTable;
    myChainedTable=NULL;
}
getType();
if (!myChainedTable)
{
    if (tableType=="string")
        myChainedTable= new MyHashTable<string>(length);  
    if (tableType=="char")
        MyHashTable<char> myChainedTable(length);  // no difference with or without using new keyword
    if (tableType=="double")
        MyHashTable<double> myChainedTable(length);
    if (tableType=="float")
        MyHashTable<float> myChainedTable(length);
    if (tableType=="int")
        MyHashTable<int> myChainedTable(length);

    cout<<tableType<<" table of size "<< length<<" created"<<endl;

我尝试将类对象传递给函数而不是将其作为全局变量,但也无法使其工作。

我真正需要的是单个模板对象,它可以有:int、string、char、double、float 类型,我有 3 个需要访问模板类对象的函数,并且有 5 个不同的对象和 200 行 if每种情况的陈述听起来都是最糟糕的解决方案。 我被困了一段时间,只是不知道该怎么做,任何帮助都将不胜感激。

void getType()
{
    cout<<"Enter table type, types available: int, char, float, double, string.\n";
    tableType=getInput();
    while((tableType != "int")&&(tableType !="float")&&(tableType !="double")&&(tableType!="char")&&(tableType !="string"))
    {
        cout<<"Invalid type, please try again "<<endl;;
        tableType=getInput();
    }
}

【问题讨论】:

  • 你从哪里得到tableType?这听起来不像是模板的工作。
  • @Jefffrey 更新了我的问题,最初将 tableType 作为返回语句,在进行一些更改时更改为全局变量,但没有多大帮助。
  • 法典定义注定要失败。每个都是 if 语句的本地,并且在您退出 if 时立即被忽略!

标签: c++ templates


【解决方案1】:

模板在编译时解析。您的容器类型在运行时解析。模板显然不是这里的解决方案。我首先想到的是 boost::anystd::vector 的组合。

【讨论】:

  • 嗯,这是一个赋值,我不能使用 c++14(模板变量会帮助我),也不能使用 c++11,我不会梦想使用 boost ;/,模板应该很容易成为分配的一部分,但我现在被困了一天,模板已经完成,如果我定义单一类型,一切正常,但用户需要能够动态更改数据类型(删除当前对象)并且只有一个对象需要存在。一定有办法的,我是不是太复杂了?
【解决方案2】:

您的问题是模板和变体之间的边界。

模板是编译时。所以你必须在编译时为你的对象选择你想要的类型。您的条件方法行不通(请参阅 cmets to question)。

另一方面,您似乎需要在运行时动态选择类型。

如果你想继续模板方式:(基于cmets编辑)

您需要让所有模板都继承自一个多态基类(一个带有虚函数的通用接口)。示例:

class MyHashBase  // common base class for all templates
{
public:
    virtual void addElement(void *ptrelem) = 0;   // adding an element must be implemented by template. With void* since future template type unknown from base class
    virtual void displayAll() = 0; 
};

然后模板需要实现虚函数:

template <class T>
class MyHashTable : public MyHashBase
{
public:
    unsigned short tableSize;
    vector<T>* myTable;        // I leave it as it is, but you could implement these as vector<T> instead of vector<T>* 
    vector<T>* deletionTable;

    MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]), deletionTable(new vector<T>[tableSize]), tableSize(tableSize)
    { }
    void addElement(void* ptrelem)
    {   myTable->push_back(*reinterpret_cast<T*>(ptrelem));  }   // reinterpret the void* of the common interface as a T* 
    void displayAll()
    { copy(myTable->begin(), myTable->end(), ostream_iterator<T>(cout, "\n")); }
};

然后你可以让你的myChainedTable 成为一个指向公共基本类型的指针,并以你对字符串大小写的方式初始化这个指针(即使用new)。

MyHashBase *myChainedTable = nullptr; 
//...
if (tableType == "string")
    myChainedTable = new MyHashTable<string>(length);
else if (tableType == "double")
    myChainedTable = new MyHashTable<double>(length);
//...

然后您可以使用通用 API,例如,如果 tableType"double"

double d1 = 3.1415, d2 = 1.4142; 
myChainedTable->addElement(&d1);   // ATTENTION: you must ensure to provide pointer to the correct data type
myChainedTable->addElement(&d2);
myChainedTable->displayAll();

如果在调用代码中需要的话,你肯定会有一个 coupe知道调用者的类型)。

但是,对基类的常用功能使用单个签名很麻烦。为了使虚拟化成为可能,您需要通过 void* 指针传递参数,这不是很好而且容易出错。

变体的替代方式

您还可以使用 boost variants 来管理具有动态类型定义的对象。

在这种情况下,您不需要自己的数据结构模板。您将使用 boost::variant&lt; int, std::string, ... &gt; 类型的元素创建一个 MyHashTable

然后,如果您知道对象的类型(如在您的myChainedTable 中),则可以通过使用:boost::get&lt;int&gt; (element)(或boost::get&lt;string&gt;(),...)来访问该对象的正确值。

如果您不知道元素的类型,您可以使用“访问者”的概念根据类型自动选择适当的函数来执行。

编辑:与联合的替代方式:

如果您不允许使用变体,另一种选择是使用union。我不知道您分配的主题,但是您可以选择是使用联合来定义元素(如变体,没有模板)还是像您一样使用模板类型,但将 myChainedTable 定义为指向不同模板实例的指针的联合。但是是的,它需要很多ifs...

【讨论】:

  • Duh ;/ 我希望我只是错过了一些明显的东西,变体听起来不错,但我不能使用 boost.Union 看起来就像花哨的数组,我仍然需要一堆 if 语句才能知道哪个打电话,但我想总比没有好。你能给我一个例子指针方法的外观吗?我已经在使用指针调用我的类,因为我的原始声明是一个指针,但我不确定如何将一个指针变成 5 个对象
  • 我用代码编辑了 clera 这个选项的工作原理。
  • 干杯,我放弃了,刚刚创建了 5 个不同的对象和巨大的 if 语句填充函数来处理它们之间的切换,如果我有时间,我会尝试使用你的第一个示例进行更改。
猜你喜欢
  • 2013-04-11
  • 2013-12-01
  • 1970-01-01
  • 2011-02-17
  • 2022-11-12
  • 2017-10-01
相关资源
最近更新 更多