页面基本上是一个固定大小的类型数组 - 但它提供了其他功能,这对于这个问题并不重要。具体来说,每个页面都有一个recordOffset
,这意味着页面的记录ID是顺序的,并从此索引开始(页面可以被视为较大数组的一个谨慎的任意段)
class AbstractPage
{
protected:
unsigned int recordOffset;
public:
AbstractPage(unsigned int recordOffset);
virtual ~AbstractPage();
// a mixture of pure and non-pure virtual functions
virtual string toString() const;
virtual unsigned int getCount() const = 0;
virtual PageType pageType() const = 0;
};
class IntegerPage : public AbstractPage
{
public:
vector<int> data;
IntegerPage(const vector<int>& data);
virtual ~IntegerPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
class FloatPage : public AbstractPage
{
public:
vector<float> data;
FloatPage(const vector<float>& data);
virtual ~FloatPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
我不想为此使用模板,因为这些页面被使用喜欢这个;
LinkedList<AbstractPage> pages;
在大多数情况下,我将使用AbstractPage
提供的界面方法与页面进行交互。当我需要直接读/写数据时,我将分别知道类型并使用:
dynamic_cast<FloatPage>(abstractPage).data[0] = 12.34;
到目前为止一切顺利,但这就是困境;我需要扩展每个类型以创建页面的索引版本:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
};
class IndexedIntegerPage : public AbstractIndexedPage, public IntegerPage
{
};
现在我希望能够做到这一点:
AbstractIndexedPage sort(const AbstractPage& page)
{
// Sorting will swap around the data and therefore we need to keep track of the
// record IDs in an Indexed page.
// If the incoming concrete type is IntegerPage, the output will be
// IndexedIntegerPage
}
问题是返回的对象没有AbstractPage
的接口:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getCount(); // can't do this!
dynamic_cast<AbstractPage>(sortedPage).getCount() // can do this, but pretty messy
从我所读到的除了select case之外的所有内容中的多重继承意味着你的代码基本上设计得很糟糕。在这种情况下,有两个非接口的多重继承,这两个类都有一个构造函数(和虚拟析构函数),但只会直接处理它们提供的实例变量。
我的选择是:
AbstractIndexedPage
扩展AbstractPage
并使用virtual
继承,因为现在有两个AbstractPage
。但这将给我完整的界面。但这不是一个顽皮的黑客吗?data
和recordIds
中复制IndexedIntegerPage
或IntegerPage
个实例变量即可提供相同的功能,而无需继承。由于
答案 0 :(得分:2)
您可以使用委派来完成这项工作。例如,在AbstractIndexedPage
:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
AbstractClass* getPage() { return page;};
private:
AbstractClass *page;
};
并做类似的事情:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getPage()->getCount(); // can't do this!
当然,验证所有可能的错误或遗漏。
P.S。有人会告诉你使用智能指针,我会同意他们,但为了简单起见,我只使用普通指针
答案 1 :(得分:1)
我打算在评论中发帖,但代码看起来很糟糕。您可以考虑在较低级别进行抽象:创建AnyType
,并根据它创建一个页面类型:
union AnyType {
float f;
int i;
};
class AnyPage : public AbstractPage
{
public:
enum PageDataType {FloatPage, IntPage};
vector<AnyType> data;
AnyPage(const vector<int>& data); //creates an 'IntPage'
AnyPage(const vector<float>& data); //creates a 'FloatPage'
virtual ~AnyPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
private:
PageDataType myType;
};
然后您可以创建AnyPage
的链接列表,如您所说,您已经知道在要访问数据时要处理的页面类型:
anyPage.data[0].f = 12.34;
然后,对于索引变种,它不再是多重继承:
class AnyIndexedPage : public AnyPage
{
public:
// this is instead of the recordOffset of AnyPage
vector<unsigned int> recordIds;
};