如何让模板 typename class 的两个(或更多)实例使用相同的函数

How to have two (or more) instances of a template typename class use the same function

我想知道是否有可能有一个 class 使用 template<typename T> 和 'typename T' 默认使用的功能。我举个例子:

Header:

includes all here
extern template class Object<rectangleBase>
extern template class Object(circleBase>

struct rectangleBase
{
    int width, height;
    int posX, posY;
};

struct circleBase
{
    int radius;
    int posX, posY;
};

template<typename T>
class Object {
public:
    Object();
    ~Object();

    void movePos(int x, int y);

    void setPos(int x, int y);

    T& returnObject() {
        return object;
    }
private:
    T object;
};

来源:

includes all here
template class Object<rectangleBase>
template class Object<circleBase>

Object<rectangleBase>::Object() { 
    rectangleBase* newObject;
    newObject = new rectangleBase;
    object = *newObject;
}

Object<circleBase>::Object() {
    circleBase* newObject;
    newObject = new circleBase;
    object = *newObject;
}

void Object::movePos(int x, int y) { //here
    object.posX += x;
    object.posY += y;
}

void Object::setPos(int x, int y) { //here
    object.posX = x;
    object.posY = y;
}

有了 setPos 和 movePos 函数,<rectangleBase><circleBase> 是否可以使用相同的函数,而不是我必须将相同的代码写出两次,因为它们会使用完全相同的相同的代码,我已经显示了函数在代码中的位置。

如果这不可能,是否有替代方案?

是的,你可以:

template <typename T>
void Object<T>::movePos(int x, int y) {
    object.posX += x;
    object.posY += y;
}

甚至您的构造函数也可以使用这种方法:

template <typename T>
Object<T>::Object() {
    // This in fact does nothing really different than the default
    // constructor of object but leaks one instance of T.
    T* newObject;
    newObject = new T;
    object = *newObject;
}

模板通常需要头文件中的整个实现,但如果您接受的类型有限,则可以显式实例化 classes,然后您可以在源文件中实现:

在头文件中(定义class之后的任何地方):

extern template class Object<rectangleBase>;
extern template class Object<circleBase>;

在源文件中(定义方法后的任何位置):

template class Object<rectangleBase>;
template class Object<circleBase>;

rectangleBasecircleBase 之外的任何其他类型都不适用于此设置。

我不确定你的问题是什么。您应该简单地实现您的功能,实例化模板并使用您的对象。

我试过了,这个,可以。请看一看:http://ideone.com/717044

#include <stdio.h>

struct rectangleBase
{
    int width, height;
    int posX, posY;
};

struct circleBase
{
    int radius;
    int posX, posY;
};

template<typename T>
class Object {
public:

    Object() { }
    ~Object() { }

    void movePos(int x, int y)
    {
        object.posX += x;
        object.posY += y;
    }

    void setPos(int x, int y)
    {
        object.posX = x;
        object.posY = y;
    }

    T& returnObject() { return object; }

private:
    T object;
};

int main(int argc, char ** argv)
{
    Object<rectangleBase> a;
    Object<circleBase> b;
    b.setPos(1,2);
    printf("px: %d", b.returnObject().posX);
}

如果您对函数编译器会生成多少个实例感兴趣, (例如:您的函数代码很大),很可能编译器会生成与您拥有的许多不同实例一样多的相似代码实例。优化器可能会折叠其中的一些。但是优化器是否会这样做 - 这很难说。

直接使用模板主体中参数类型的字段、方法、枚举等的方法称为使用依赖类型。是的,这种方法使得很难或不可能使用没有此字段或成员函数的类型实例化您的模板。然而这种模式被广泛使用。

为多种不同的数据类型(简而言之,泛型编程)编写相同的代码正是模板的用途。我觉得你想多了。以下内容足以满足您的用例:

template<typename T>
class Object {
public:
    Object()
    : object()
    { }

    void movePos(int x, int y) {
        object.posX += x;
        object.posY += y;
    }

    void setPos(int x, int y) {
        object.posX = x;
        object.posY = y;
    }

    T& returnObject() {
        return object;
    }
private:
    T object;
};

这就是您所需要的。这将适用于任何可默认构造的 T,然后如果 T 具有这两个成员变量,则可以调用 movePossetPos。您根本不需要声明专业化。鉴于上述情况,以下工作正常:

Object<rectangleBase> r;
r.setPos(5, 6);

Object<circleBase> c;
c.setPos(10, 20);
s.movePos(10, 10);