模板基类型继承

时间:2015-04-25 15:34:27

标签: c++ templates inheritance

我有以下课程:

class Box{...};
class MyBox : public Box{...};

模板:

template <type T>
class ObjectManager{...};

我在其他课程中使用的是:

class Engine{
    ObjectManager<Box> * manager = nullptr;
    ...
};

然后我扩展(实现)Engine接口:

class MyEngine : public Engine{...}

在该实施中(不早!)我知道manager应该是这样的:

MyEngine::MyEngine(){
    manager = new ObjectManager<MyBox>();
}

但是由于类型冲突(ObjectManager<Box>ObjectManager<MyBox>之间的转换),即使MyBox继承自Box,这也会给我一个错误。

有没有解决这个问题的方法? 我不想修改 BoxMyBox,{{1 }和ObjectManager类。

4 个答案:

答案 0 :(得分:1)

Templatize Engine然后继承MyEngine with Engine,携带你想要的Box模板实例。像这样:(http://codepad.org/SZMSbCRB

#include <iostream>

using namespace std;

class Box{
};

class MyBox : public Box{
};

template <typename T>
class ObjectManager{

};

template <typename T>
class Engine{
    public:
    ObjectManager<T*> * manager;
};

class MyEngine : public Engine<MyBox>{

    public:
    MyEngine(){
    manager = new ObjectManager<MyBox*>();
    cout<<"myEngine created"<<endl;
    }
};

int main() {
     MyEngine eng = MyEngine();  
     return 0; 
}

这里的好处是,如果明天你创建一个新的Box,即MyBox2,并且想要为此创建一个自定义引擎MyEngine2,只需继承MyEngine : public Engine <MyBox2>。只需确保处理类型转换。

据我记忆,在Java中,您可以将Engine声明为类似Engine<extends T>的内容,它允许您使用提供的模板T的任何子类型实例化Engine。这是一种更安全,更好的方法,但我不知道C ++是否提供了类似的东西。

希望它有所帮助。

答案 1 :(得分:0)

如果不以某种方式改变设计,这是不可能的。 ObjectManager<Box>只是不是ObjectManager<MyBox>而且它不是它的基类,但只有模板参数是基础的并且相互派生。

如果ObjectManager使用指针或智能指针作为“托管”对象......

template <class T> 
class ObjectManager
{
  T * object;
public:
  ObjectManager(T * ptr) : object(ptr) { } 
};

...您可以使用指向派生对象的指针构造ObjectManager

class MyEngine : public Engine 
{ 
  MyEngine()
  { 
    manager = new ObjectManager<Box>(new MyBox);
  }
};

如果Engine是抽象界面,您还可以在MyEngine中拥有自己的经理并使用它来实施MyEngine

class MyEngine : public Engine
{
  ObjectManager<MyBox> * mymanager;
  MyEngine() : Engine(), mymanager(new ObjectManager<MyBox>)
  {  }
};

答案 2 :(得分:0)

考虑为ObjectManager使用包装 如果NOTET不兼容,BaseT会标记无法编译的行。

假设:

template<class T>
ObjectManager{
    T* objectAtIndex(size_t i); // As an example.
    void insertAtIndex(T* object, size_t i); // As an example.
};

打包机:

template<class T, class BaseT>
class MyObjectManager
{
public:
    ObjectManager<BaseT>* manager; // public for simplicity only!

    T* objectAtIndex(size_t i){
        return static_cast<T*>(manager->objectAtIndex(i)); // <- NOTE
    }

    void insertAtIndex(T* object, size_t i){
        manager->insertAtIndex(object, i); // <- NOTE
    }
};

用法:

class MyEngine : public Engine 
{
    MyObjectManager<MyBox, Box> my_manager;

    MyEngine(){
        // Setup the manager(s).
        manager = new ObjectManager<Box>();
        my_manager.manager = manager;

        // Example usage.
        my_manager.insertAtIndex(new MyBox(), 0);
        MyBox* p = my_manager.objectAtIndex(0);
    }
};

答案 3 :(得分:0)

您可以提供支持转换的实现。这应该类似于std::unique_ptr可以从派生指针类型隐式转换为基指针类型的方式。

示例代码

#include <iostream>
#include <memory>
#include <vector>

class Box
{
public:
    virtual ~Box() {}

    virtual void foo() = 0;
};

class MyBox : public Box
{
public:
    virtual ~MyBox() {}

    virtual void foo() override
    {
        std::cout << "MyBox::foo()\n";
    }
};

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

    void add(T *object)
    {
        objects.emplace_back(object);
    }

    template<typename U>
    ObjectManager<T> &operator=(ObjectManager<U> &other)
    {
        return *this;
    }

    std::size_t size() const
    {
        return objects.size();
    }

    T& operator[](std::size_t i)
    {
        return *objects[i];
    }

private:
    std::vector<std::unique_ptr<T>> objects;
};

class Engine
{
public:
    ObjectManager<Box> manager;
};

class MyEngine : public Engine
{
public:
    MyEngine()
    {
        manager = ObjectManager<MyBox>();
        manager.add(new MyBox());
    }
};

int main()
{
    MyEngine engine;

    for (std::size_t i = 0; i < engine.manager.size(); ++i)
    {
        engine.manager[i].foo();
    }

    return 0;
}

示例输出

MyBox::foo()

另一个例子

这可能有助于说明如何实施转化。

示例代码

template<typename T>
class MyPointer
{
public:
    MyPointer() :
        mPointer(nullptr)
    {
        // Do nothing
    }

    template<typename U>
    MyPointer(MyPointer<U> &other) :
        mPointer(other.mPointer)
    {
        other.mPointer = nullptr;
    }

    MyPointer(T *pointer) :
        mPointer(pointer)
    {
        // Do nothing
    }

    template<typename U>
    MyPointer<T> &operator=(MyPointer<U> &other)
    {
        mPointer = other.mPointer;
        other.mPointer = nullptr;
        return *this;
    }

    ~MyPointer()
    {
        delete mPointer;
    }

    T* operator->()
    {
        return mPointer;
    }

private:
    template<typename U> friend class MyPointer;

    T* mPointer;
};

int main()
{
    {
        MyPointer<MyBox> myBox(new MyBox());

        MyPointer<Box> box;
        box = myBox;
        box->foo();
    }

    {
        MyPointer<MyBox> myBox(new MyBox());
        MyPointer<Box> box(myBox);
        box->foo();
    }

    return 0;
}

示例输出

MyBox::foo()
MyBox::foo()