我正在尝试创建一个返回接口矢量的接口,同时使用它在另一侧实现.
我知道它不清楚,所以这里有例子:
class IComponent
{
public:
virtual ~IComponent() {}
virtual int getValue() const = 0;
};
class ICollection
{
public:
virtual ~ICollection() {}
virtual IComponent* getComp() = 0;
};
class Component : public IComponent
{
public:
virtual int getValue() const { return 42; }
};
class Collection : public ICollection
{
public:
Collection()
{
m_comp = new Component();
}
virtual Component* getComp()
{
return m_comp;
}
private:
Component* m_comp;
};
这种编译和工作,因为Component *被隐式转换为IComponent *.这允许我使用完全实现的Collection和Component.
#include <vector>
class IComponent
{
public:
virtual ~IComponent() {}
virtual int getValue() const = 0;
};
class ICollection
{
public:
virtual ~ICollection() {}
virtual std::vector<IComponent*> &getComp() = 0;
};
class Component : public IComponent
{
public:
virtual int getValue() const { return 42; }
};
class Collection : public ICollection
{
public:
Collection()
{
m_comp.push_back(new Component());
m_comp.push_back(new Component());
}
virtual std::vector<Component*> &getComp()
{
return m_comp;
}
private:
std::vector<Component*> m_comp;
};
但是这次我无法使用完整实现的Collection和Component.
当然很容易理解为什么,因为Component *是IComponent *,但严格来说,std :: vector< Component *>不是std :: vector< IComponent *>.此问题也适用于所有模板类型,如迭代器,smart_ptr等…
相反,在Collection :: getComp()中,我必须返回一个std :: vector< IComponent *>.我可以在返回它时投射m_comp(我甚至不确定它是否有效,它不是一个右值?).我还可以存储2个向量,一个Component *和一个IComponent *,并保持它们同步,但这是我认为的丑陋代码.
是否有一些解决方法,或某种我不知道处理它的方式?
更多细节:
我真正想要的是能够在集合中使用Component.如果我将m_comp更改为std :: vector< IComponent *>它将起作用的getComp()返回类型,但我将*使用指向IComponent的指针,而不是指向Collection中的Component.
所以是的,我可以同步两个向量,或者在getComp()中创建一个副本,但我想知道是否有更好的方法.
事件更多细节:
以下是我想如何使用它的示例:
(我只是在Component中添加了getDouble()方法并在Collection中调用它)
#include <iostream>
#include <vector>
class IComponent
{
public:
virtual ~IComponent() {}
virtual int getValue() const = 0;
};
class ICollection
{
public:
virtual ~ICollection() {}
virtual std::vector<IComponent*> &getComp() = 0;
};
class Component : public IComponent
{
public:
virtual int getValue() const { return 42; }
double getDouble() const { return 3.14; }
};
class Collection : public ICollection
{
public:
Collection()
{
m_comp.push_back(new Component());
m_comp.push_back(new Component());
}
// Impossible because it does not override the good method
virtual std::vector<Component*> &getComp()
{
std::cout << m_comp[0]->getDouble() << std::endl;
return m_comp;
}
private:
std::vector<Component*> m_comp;
};
如果我更改了返回类型,Collection将变为:
class Collection : public ICollection
{
public:
Collection()
{
m_comp.push_back(new Component());
m_comp.push_back(new Component());
}
virtual std::vector<IComponent*> &getComp()
{
// This time this line is impossible without cast
// because m_comp[0] is IComponent*
std::cout << m_comp[0]->getDouble() << std::endl;
return m_comp;
}
private:
std::vector<IComponent*> m_comp;
};
一个解决方案是这样的:
class Collection : public ICollection
{
public:
Collection()
{
// Useless and redundant code here
m_comp.push_back(new Component());
m_icomp.push_back(m_comp.back());
m_comp.push_back(new Component());
m_icomp.push_back(m_comp.back());
}
// Impossible because it does not override the good method
virtual std::vector<IComponent*> &getComp()
{
std::cout << m_comp[0]->getDouble() << std::endl;
return m_icomp;
}
private:
// Duplicated storage for "nothing"
std::vector<Component*> m_comp;
std::vector<IComponent*> m_icomp;
};
在我看到的回复中,有一些关于实现pop()和push()方法的东西,但在我的项目中我使用的是Map而不是Collection,并且有块的向量.这允许通过执行map [y] [x]来访问块.
问题是存储是固定的.一种解决方案是添加方法getBlock(size_t x,size_t y).但是我希望看到我能用第一种情况做的最好:)
解决方法:
不确定这个解决方案是否适用于您的情况但是……如何在ICollection中将Component派生类作为模板参数传递?
不完全是奇怪的重复模板模式,但类似的东西.
我的意思是,像
template <typename CompT>
class ICollection
{
public:
virtual ~ICollection() {}
virtual std::vector<CompT*> &getComp() = 0;
};
所以收藏成了
class Collection : public ICollection<Component>
{
public:
Collection()
{
m_comp.push_back(new Component());
m_comp.push_back(new Component());
}
virtual std::vector<Component*> &getComp()
{
return m_comp;
}
private:
std::vector<Component*> m_comp;
};
甚至,如果您在模板类中转换Collection
template <typename CompT>
class Collection : public ICollection<CompT>
{
public:
Collection()
{
m_comp.push_back(new CompT());
m_comp.push_back(new CompT());
}
virtual std::vector<CompT*> &getComp()
{
return m_comp;
}
private:
std::vector<CompT*> m_comp;
};