C++ 从嵌套类的接口派生
C++ Deriving from interface with nested class
我正在编写代码来处理"Foo"类型的对象。foo 是一种容器类型,为了提供对其元素的高效和抽象访问,它提供了一个类型Element
的嵌套类。Element
包装对象在容器中的位置。
现在,"Foo"可能有不同的实现,所以我正在编写一个抽象基类FooInterface
,为它们提供一个通用接口。问题是每个实现可能需要定义自己的Element
类型。例如,一个实现可能将其数据保存在向量中,以便其Element
包装向量迭代器,而另一个实现包含列表,其Element
包装列表迭代器。
我已经制定了一个使用空指针工作的解决方案。实质上,基类定义了一个包装 void 指针的Element
类。FooInterface
的不同实现可以将 void 指针转换为它们用来表示元素的任何类型。目前,忽略内存泄漏:
class FooInterface
{
public:
class Element {
void* payload;
public:
Element(void* payload) : payload(payload) {}
void* getPayload() const { return payload; }
};
virtual void say_element(Element) = 0;
virtual Element getElement() = 0;
};
class FooOne : public FooInterface
{
public:
virtual void say_element(Element element)
{
std::cout << "FooOne says: " <<
* (int *) element.getPayload() << "." << std::endl;
}
virtual Element getElement()
{
return Element(new int(42));
}
};
class FooTwo : public FooInterface
{
public:
virtual void say_element(Element element)
{
std::cout << "FooTwo says: " <<
* (std::string*) element.getPayload() << "." << std::endl;
}
virtual Element getElement()
{
return Element(new std::string("This is a test"));
}
};
void say(FooInterface& foo)
{
FooInterface::Element el = foo.getElement();
foo.say_element(el);
}
int main()
{
FooOne foo_one;
FooTwo foo_two;
say(foo_one);
say(foo_two);
return 0;
}
虽然这行得通,但似乎一定有更好的方法。我的理解是,如果可能的话,应该避免使用空指针。那么,这是实现这一目标的最佳方法吗?
编辑:
诚然,我在描述我在这篇文章中试图做的事情方面做得很差。尽管如此,这些答案还是有助于我思考的,我已经在这里设计了一个我认为不错的解决方案。
你可以FooInterface
做一个模板,并将Element
应该存储的任何内容作为模板参数传递:
template <typename Payload>
class FooInterface
{
public:
class Element {
Payload payload;
public:
Element(Payload payload) : payload(payload) {}
Payload getPayload() const { return payload; }
};
virtual void say_element(Element) = 0;
virtual Element getElement() = 0;
};
然后,您的子类必须将适当的模板参数传递给超类:
class FooOne : public FooInterface<int>
{
public:
virtual void say_element(Element element)
{
std::cout << "FooOne says: " <<
element.getPayload() << "." << std::endl;
}
virtual Element getElement()
{
return Element(42);
}
};
如果您的目标是让每个容器始终如一地将其元素类型公开为FooXXX::Element
,那么您可以对FooInterface
进行寺庙化并为Element
添加一个 typedef
template<class elem>
class FooInterface {
public:
typedef elem Element;
/*... */
};
class FooOneElement {
/*... */
};
class FooOne : public FooInterface<FooOneElement> {
/*... */
};
如果您知道将使用的不同类型的数据类型,为什么不在派生类中声明相应的变量,然后使用它们呢?基类中不需要 void*。另外,我认为,您可以避免在所有派生类中使用 virtual 关键字,相反,您可以在要在基类中使用的函数之前指定 virtual。
或者,您可以使用模板来定义具有不同类型参数的相同函数。 参考这个,它真的很有用
http://www.codeproject.com/Articles/5351/Simulation-of-Virtual-Function-with-Template
谢谢你
你想要一个container, [...] to provide efficient and abstracted access to its elements
。这是通用(虚拟)和 高效(模板)实施。由于抽象,您将失去效率(与标准容器相比)。将元素的访问和迭代放入容器的元素中(在我看来)是完全错误的设计。此外,您的解决方案(如前所述)远非类型安全。
类型安全的解决方案可能是:
// Library
// =======
#include <memory>
#include <stdexcept>
template <typename Element>
class BasicElements
{
public:
typedef Element element_type;
protected:
struct Implementation {
virtual element_type& get() = 0;
virtual bool first() = 0;
virtual bool next() = 0;
virtual bool last() = 0;
virtual void end_of_elements() = 0;
virtual void insert(const element_type&) = 0;
};
template <typename Container>
struct BidirectionalImplementation : Implementation {
typedef Container container_type;
typedef typename container_type::value_type value_type;
typedef typename container_type::iterator iterator;
container_type elements;
iterator position;
BidirectionalImplementation()
: position(elements.begin())
{}
virtual bool first() {
position = elements.begin();
return (position != elements.end());
}
virtual bool next() {
if(position != elements.end())
return (++position != elements.end());
return false;
}
virtual bool last() {
position = elements.end();
if(position != elements.begin()) {
--position;
return true;
}
return false;
}
virtual void end_of_elements() {
position = elements.end();
}
};
template <typename Container>
struct SequentialImplementation : BidirectionalImplementation<Container> {
private:
typedef BidirectionalImplementation<Container> Base;
public:
typedef typename Base::container_type container_type;
typedef typename Base::value_type value_type;
typedef typename Base::iterator iterator;
public:
virtual element_type& get() {
if(this->position == this->elements.end())
throw std::out_of_range("Position");
return *this->position;
}
virtual void insert(const element_type& e) {
this->position = this->elements.insert(this->position, e);
++this->position;
}
};
template <typename Container>
struct MapImplementation : BidirectionalImplementation<Container> {
private:
typedef BidirectionalImplementation<Container> Base;
public:
typedef typename Base::container_type container_type;
typedef typename Base::value_type value_type;
typedef typename Base::iterator iterator;
public:
virtual element_type& get() {
if(this->position == this->elements.end())
throw std::out_of_range("Position");
return this->position->second;
}
virtual void insert(const element_type& e) {
this->position = this->elements.insert(this->position, value_type(e.key(), e));
}
};
template <typename Other>
BasicElements(std::shared_ptr<Other> p)
: m_self(std::static_pointer_cast<Implementation>(p))
{}
public:
element_type& get() { return m_self->get(); }
const element_type& get() const { return m_self->get(); }
bool first() const { return m_self->first(); }
bool next() const { return m_self->next(); }
bool last() const { return m_self->last(); }
void end_of_elements() const { m_self->end_of_elements(); }
void insert(const element_type& e) { m_self->insert(e); };
private:
std::shared_ptr<Implementation> m_self;
};
/// PRECONDITION The container fulfills (a subset of) the requirements
/// for a standard (bidirectional) sequence container.
template <typename Container>
class SequentialElements : public BasicElements<typename Container::value_type>
{
private:
typedef BasicElements<typename Container::value_type> Base;
protected:
typedef typename Base::template SequentialImplementation<Container> Implementation;
public:
SequentialElements()
: Base(std::make_shared<Implementation>())
{}
};
/// PRECONDITION The container fulfills (a subset of) the requirements
/// for a standard (bidirectional) associative container.
/// The mapped type of the container has a member K key() const,
/// where K is convertable to the key_type of the container.
template <typename Container>
class MapElements : public BasicElements<typename Container::mapped_type>
{
private:
typedef BasicElements<typename Container::mapped_type> Base;
protected:
typedef typename Base::template MapImplementation<Container> Implementation;
public:
MapElements()
: Base(std::make_shared<Implementation>())
{}
};
// Test
// ====
#include <iostream>
#include <list>
#include <vector>
#include <map>
class Element
{
public:
Element(int value)
: m_key(value), m_value(value)
{}
Element(int key, int value)
: m_key(key), m_value(value)
{}
int key() const { return m_key; }
const int& value() const { return m_value; }
int& value() { return m_value; }
private:
int m_key;
int m_value;
};
inline bool operator < (const Element& a, const Element& b) {
return a.key() < b.key();
}
int main() {
typedef SequentialElements< std::vector<Element> > vector_elements;
typedef SequentialElements< std::list<Element> > list_elements;
typedef MapElements< std::map<int, Element> > map_elements;
vector_elements v;
v.insert(Element(2));
v.insert(Element(1));
v.insert(Element(0));
list_elements l;
map_elements m;
if(v.first()) {
do {
l.insert(v.get());
m.insert(v.get().value());
}
while(v.next());
}
const char* ContainerName[] = {
"Vector",
"List",
"Map"
};
typedef std::vector<BasicElements<Element>> container_collection;
container_collection collection;
collection.push_back(v);
collection.push_back(l);
collection.push_back(m);
for(unsigned i = 0; i < collection.size(); ++i) {
const BasicElements<Element>& elements = collection[i];
std::cout << ContainerName[i] << "n";
if(elements.first()) {
do {
std::cout << elements.get().value() << 'n';
}
while(elements.next());
}
}
}
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 如何在基类中定义静态接口,并确保该接口必须在派生类中实现
- C 结构实现派生接口
- 如何从接口获得派生类
- 接口会议派生的类功能而无需铸造
- 共享接口类和 C++ 派生类中的默认参数值
- 在派生类接口中隐藏基类的特定函数
- C++ 从嵌套类的接口派生
- C#派生的接口在C++中无法正常工作
- 定义多个派生接口成员
- 从接口派生的模板 - 多态性停止工作
- 具有显式派生方法的C++接口
- 从Const引用接口到派生类的转换
- 如何创建从另一个派生的两个ATL接口
- CLR 探查器:COM 样式的强制转换和从派生接口调用函数
- 具有扩展接口的派生类的集合.如何在没有动态强制转换的情况下访问派生接口
- c++:通过基类接口构造派生对象
- IUknown 派生接口上的虚拟析构函数
- 将从接口派生的类的实例添加到接口指针数组中
- 描述从多个接口派生的对象