2013-02-24 120 views
0

我想将一个类从“普通”类转换为模板类,但我不明白正确的语法。下面是一个(大大简化)我开始的例子。这是Visual Studio 2010,C++,面向x64体系结构,Windows 7。如何将“正常”C++类转换为模板?

目标是将类T重写为模板,以处理TEntry或类TEntry的新类,OtherTEntry,具有相同的成员函数,但具有不同的数据成员。

我很感谢关于如何做到这一点的建议。如果可能的话,我想将头文件和实现文件分开。我特别坚持对局部变量T *的引用,以及如何正确使用sizeof()。

在文件钍:

class T 
{ 
    T(void); 
    T(G *pGIn, const unsigned long s, char nIn); 
    ~T(void); 

    // Member functions 
    public: 
    bool Expand(const unsigned long newS); 
    void Empty(void); 

    private: 
    G *pG; 
    char n; 
    unsigned long s; 
    int f; 
    TEntry *p; 
}; 

在文件TEntry.h:

class TEntry 
{ 
    // Constructors 
    public: 
    TEntry(); 
    TEntry(int l); 

    // Member functions 
    public: 
    void Relocate(int delta); 

private: 

    // Data members 
    int k; 
    TEntry *p; 
}; 

在文件T.cpp:

T::T() 
{ 
    p=NULL; s=0; pG=NULL; 
    Empty(); 
    return; 
} 

T::T(G *pGIn, const unsigned long m, char nIn) 
{ 
    pG=pG; n=nIn; 
    return; 
} 

T::~T(void) 
{ 
    if(p!=NULL) 
     delete[] p; 
    return; 
} 

bool T::Expand(const unsigned long newS) 
{ 
    T *pBefore=p; 
    p=(T *)_realloc_dbg(p, newS*sizeof(T), _NORMAL_BLOCK,__FILE__,__LINE__); 
    s=newS; 
    return p!=NULL; 
} 

void T::Empty() 
{ 
    f=0; 
    return; 
} 

在文件TEntry.cpp:

T::T() 
{ 
} 

T::T(int i) 
{ 
    k=i; 
} 

void T::Relocate(int delta) 
{ 
    k+=delta; 
    return; 
} 
+0

调用类T是一个非常糟糕的选择。请张贴您尝试过的内容,很难说出您没有展示时做错了什么。 – Mat 2013-02-24 08:00:05

+0

是否有任何不使用'std :: vector'的理由? – 2013-02-24 08:45:30

+0

请放心,我的实际班级并没有被命名为T.我现在有一个完整的工作对班,但是我只显示了我的代码的一小部分,刚够问我的问题。 – Woody20 2013-02-24 17:47:52

回答

0

我想保持头和实现文件分开

虽然可以做到这一点,这是一个有点一场噩梦。通常最好将模板的所有部分放在一起。

你可能需要的是这样的:

template< typename TYPE > class T 
{ 
    // ... 
    TYPE* p; 
}; 

然后可以使用sizeof(TYPE)

你不能做的一件事,而且永远不应该做的是将realloc与new和delete混合。 C++不支持用new和delete分配的内存的重新分配。相反,它具有容器,如std::vector可以为您管理内存。

而且,如前所述,一个字母类和变量名称不是一个好主意。 :)

+0

我将不得不检查这种使用realloc。在Visual Studio中,'new'运算符使用malloc。 – Woody20 2013-02-24 17:53:14

+0

无论内部使用什么或不使用内容。你不能安全地混合C(malloc/realloc/free)和C++(new/delete)内存分配策略。 – 2013-02-24 18:57:16

+0

什么是不安全的混合他们?在这种情况下,可移植性不是问题。 – Woody20 2013-02-24 19:58:00

1

最简单的方法是从一个完整的,工作的,非模板版本的T开始,它是根据您稍后要在模板中使用的一种类型编写的(此处明显选择:TEntry) 。

一旦你有一个工作实现,你可以将其转换为模板。

  1. 为模板参数选择一个名称。类型参数的通常名称是T,但该名称已在您的项目中使用,因此我将使用U
  2. 通过模板参数的名称替换内TTEntry所有出现(U
  3. 模板头部添加到T类定义:

    template <class U> 
    class T { 
        //... 
    
  4. 模板头部添加到每个成员定义在类定义之外的T

    template <class U> 
    «return type» T<U>::«member specification» //... 
    
  5. En确保所有模板代码都在头文件中(直接或间接通过#include指令。模板不支持单独编译头文件和源文件。
+0

谢谢你,这个评论是最有帮助的。我已经有了T和TEntry的工作实现。至于“单独编译”,这不是我想要的,只是单独的文件。 #include的作用是将头文件与实现文件结合起来。 – Woody20 2013-02-24 17:55:57

0

通常,最好将模板代码保存在.h文件中。如果绝对必要,可以将实现放在.cpp文件中,详情请咨询C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis,Chaprer 6。

你可以去这样的(削减不太重要的细节):

template <class T> 
class YourClass 
{ 
    YourClass() 
     : p(NULL), s(0), pG(NULL) 
    { 
     Empty(); 
    } 

    YourClass(G *pGIn, const unsigned long s, char nIn) 
    { 
     // ... implementation here 
    } 
    ~YourClass() 
    { 
     if(p!=NULL) 
      delete p; 
    } 


public: 
    bool Expand(const unsigned long newS) 
    { 
     T *pBefore=p; 
     p=(T *)_realloc_dbg(p, newS*sizeof(T), _NORMAL_BLOCK,__FILE__,__LINE__); 
     s=newS; 
     return p!=NULL; 
    } 


private: 
    G *pG; 
    char n; 
    unsigned long s; 
    int f; 
    T* p; 
}; 

几点注意事项:

  • 命名你的类模板T真是一个糟糕的主意,因为这是一个普遍的做法使用T作为模板参数名称。
  • 关于sizeof,在您的代码示例中,它不适用于模板,而是适用于通常的类,无论如何,在类,类模板或模板参数上使用sizeof应该不会有任何问题。