c++ 中的关系容器和多态性问题
如果有任何帮助,我将不胜感激。
我有一个简单的容器模板类数据集。
此外,当实例化数据集的数据集时,还有一个专门化允许不同的实现。
由于数据集的数据集是一个异构容器,因此有一个基本抽象类 List 必须为每个数据集声明一个公共接口。那就是 get()。
问题是:我无法在 List::get() 中指定返回类型,因此我需要重写后代中的 void* 返回。
我已阅读以下协方差限制:
•函数B::f返回指向T类型的类的引用或指针,并且A::f返回>。指向 T 的明确直接或间接基类的指针或引用。
• B::f 返回的指针或引用的const 或易失性限定与A::f 返回的指针或引用的const 或易失性限定相同或更少。
•B::f 的返回类型在 B::f 的声明点必须是完整的,或者可以是 B 类型。
那么,让包含的对象从同一基类派生对我来说没有用。
那么,有解决方法吗?更好的是:正确的 C++ 方法是什么?
如果你想知道,我想做的是一个“关系容器”,可以这么说。但无论如何你都不会在下面的代码中看到关系部分。
目标是存储数据,使容器不知道列表之间的任何关系。 然后我会将这些关系分开存储在一个列表中。例如:
人员列表
0 约翰
1 亚瑟
2 卡罗琳
汽车列表
0 - 福特
1 - 大众
2 - 克莱斯勒
关系列表
0 - 1;2
1 - 0;1
2 - 0;2
与关系数据库非常相似。 另外,我还有一些小问题,比如让 set() 接受 maxsize 数量的参数。使用 va_list 无法实现此目的。无论如何,也许我匆忙地经历了这一切。
最后一点:为了学习,我故意避免使用 STL,但是如果已经有这样的功能,我想知道。
多谢!
代码如下:
#include <iostream>
using namespace std;
//--------------------------------------------------//
// TRIVIAL DUMMY CLASSES
class Person
{
public:
Person(char* n, unsigned int a): _name(n), _age(a){}
char* name(){cout << "Im " << _name << endl; return _name;}
unsigned int age(){cout << "Im " << _age << " years old." << endl; return _age;}
private:
char* _name;
unsigned int _age;
} p1("john", 28), p2("Arthur", 26), p3("Caoline", 31);
class Car
{
public:
Car(char* m, unsigned int y): _model(m), _year(y){}
char* model(){cout << "Its a " << _model << endl; return _model;}
unsigned int year(){cout << "Im" << _year << " years old." << endl; return _year;}
private:
char* _model;
unsigned int _year;
} c1("Chrysler C-300", 1955), c2("Chrysler VH Charger", 1971), c3("Ford Fairlane", 1960);
//--------------------------------------------------//
class List
{
public:
List(): length(0){}
// common interface so Lists of Lists can be created
// can´t specify a return type so it returns void*
// BUT need to override it in descendants. WHY IT DOESN´T WORK?
virtual void* get(unsigned int i) = 0;
protected:
unsigned int length;
};
//--------------------------------------------------//
template <class C, unsigned int maxsize>
class Dataset: public List
{
public:
Dataset()
{
// initialize pointers to null
for(int i = 0; i < maxsize; i++){
data[i] = 0;
}
};
// C* return type is ignored
C* get(unsigned int i)
{return data[i];};
int set(C* dataIn)
{
data[length] = dataIn;
return length++;
};
protected:
C* data[maxsize];
};
template <unsigned int maxsize>
class Dataset <List, maxsize>: public List
{
public:
Dataset()
{
// initialize pointers to null
for(int i = 0; i < maxsize; i++){
data[i] = 0;
}
};
List* get(unsigned int i)
{return data[i];};
int set(List* dataIn)
{
data[length] = dataIn;
return length++;
};
protected:
List* data[maxsize];
};
//--------------------------------------------------//
int main()
{
Dataset <Person, 3> columnPerson;
// populate person list
columnPerson.set(&p1);
columnPerson.set(&p2);
columnPerson.set(&p3);
Dataset <Car, 3> columnCar;
// populate car list
columnCar.set(&c1);
columnCar.set(&c2);
columnCar.set(&c3);
Dataset <List, 10> relations; // create a list of lists
// populate it
relations.set(&columnPerson);
relations.set(&columnCar);
// getting a void* and casting it
Person* ptrPerson = (Person*) relations.get(0)->get(0);
ptrPerson->name();
int i;
cin >> i;
};
I would appreciate any help with this.
I have a simple container template class Dataset.
Also there is a specialization to allow a different implementation when a Dataset of Datasets is instantiated.
Since a Dataset of Datasets would be a heterogeneous container, there is a base abstract class List wich must declare a common interface for every Dataset. That would be get().
The problem is: I cannot specify a return type in List::get() so I need to override the void* return in descendants.
I´ve read the following restrictions for covariance:
•The function B::f returns a reference or pointer to a class of type T, and A::f returns > a pointer or a reference to an unambiguous direct or indirect base class of T.
•The const or volatile qualification of the pointer or reference returned by B::f has the same or less const or volatile qualification of the pointer or reference returned by A::f.
•The return type of B::f must be complete at the point of declaration of B::f, or it can be of type B.
Well, make the contained objects descend from the same base class is of no use to me.
So, is there a workaround to this? Better yet: what is the proper c++ way to do this?
In case you wonder, what I am trying to do is is a 'relational container', so to speak. But you won´t see the relational part in the code below anyway.
The goal is to store data keeping the container unaware of any relation beetween list.
Then I would store the relations in a list apart. For example:
Person list
0 John
1 Arthur
2 Caroline
Car list
0 - Ford
1 - Volkswagen
2 - Chrysler
Relations list
0 - 1;2
1 - 0;1
2 - 0;2
Pretty much as a relational database.
Also, i have minor side problems, like making set() to accept a maxsize number of arguments. Couldn´t achieve this with va_list. Maybe I rushed through this, anyway.
Final point: I´m deliberately avoiding STL for learning sake, BUT if there is already such functionality available I would like to know.
Thanks a lot!
The code below:
#include <iostream>
using namespace std;
//--------------------------------------------------//
// TRIVIAL DUMMY CLASSES
class Person
{
public:
Person(char* n, unsigned int a): _name(n), _age(a){}
char* name(){cout << "Im " << _name << endl; return _name;}
unsigned int age(){cout << "Im " << _age << " years old." << endl; return _age;}
private:
char* _name;
unsigned int _age;
} p1("john", 28), p2("Arthur", 26), p3("Caoline", 31);
class Car
{
public:
Car(char* m, unsigned int y): _model(m), _year(y){}
char* model(){cout << "Its a " << _model << endl; return _model;}
unsigned int year(){cout << "Im" << _year << " years old." << endl; return _year;}
private:
char* _model;
unsigned int _year;
} c1("Chrysler C-300", 1955), c2("Chrysler VH Charger", 1971), c3("Ford Fairlane", 1960);
//--------------------------------------------------//
class List
{
public:
List(): length(0){}
// common interface so Lists of Lists can be created
// can´t specify a return type so it returns void*
// BUT need to override it in descendants. WHY IT DOESN´T WORK?
virtual void* get(unsigned int i) = 0;
protected:
unsigned int length;
};
//--------------------------------------------------//
template <class C, unsigned int maxsize>
class Dataset: public List
{
public:
Dataset()
{
// initialize pointers to null
for(int i = 0; i < maxsize; i++){
data[i] = 0;
}
};
// C* return type is ignored
C* get(unsigned int i)
{return data[i];};
int set(C* dataIn)
{
data[length] = dataIn;
return length++;
};
protected:
C* data[maxsize];
};
template <unsigned int maxsize>
class Dataset <List, maxsize>: public List
{
public:
Dataset()
{
// initialize pointers to null
for(int i = 0; i < maxsize; i++){
data[i] = 0;
}
};
List* get(unsigned int i)
{return data[i];};
int set(List* dataIn)
{
data[length] = dataIn;
return length++;
};
protected:
List* data[maxsize];
};
//--------------------------------------------------//
int main()
{
Dataset <Person, 3> columnPerson;
// populate person list
columnPerson.set(&p1);
columnPerson.set(&p2);
columnPerson.set(&p3);
Dataset <Car, 3> columnCar;
// populate car list
columnCar.set(&c1);
columnCar.set(&c2);
columnCar.set(&c3);
Dataset <List, 10> relations; // create a list of lists
// populate it
relations.set(&columnPerson);
relations.set(&columnCar);
// getting a void* and casting it
Person* ptrPerson = (Person*) relations.get(0)->get(0);
ptrPerson->name();
int i;
cin >> i;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不会尝试回答实现细节,但您可以按照您的要求,从 boost.any 库。有一个关于使用它的异构容器的教程。
I'm not gonna try to answer the implementation details, but you can, as you requested, get functionality out of the boost.any library. There is a tutorial on heterogenous containers using it.
当您重写虚函数时,所有内容都必须相同(参数、名称、返回类型)。另外,您不能重写仅返回类型不同的函数(就像您尝试处理返回 C* 的函数一样。
您可能必须坚持使用 void * 并将其转换为正确的类型。当然,您'你需要知道它应该是什么类型。在正常情况下,它们需要有一个通用的接口,如果你想返回不同的类型,你就没有一个通用的接口。
When you override a virtual function, everything must be the same (parameters, name, return type). Also, you cannot override a function that differs only by return type (as you are trying to do with the one that returns C*.
You may have to stick with a void * and cast it to the proper type. Of course, you'll need to know what type it is supposed to be. You are pushing the envelope of heterogeneous containers. In normal cases, they need to have a common interface. If you want to return different types, you do not have a common interface.