只知道运行时的数据类型.如何将数据详细信息隐藏到使用它们的其他类

Only know data type at run time. How to hide data details to other classes which use them

本文关键字:隐藏 其他 详细信息 数据 运行时 数据类型      更新时间:2023-10-16

基本上,我必须使用以下语法基于输入文本文件填充对象:

float 4.55 24 2.1
int 4 6 9 0
float 5.1 6 6
//char 255 3 5

然后我需要对它们进行某种操作(例如一个简单的adion(——事先无法知道会有哪些类型的数据

我不能把它们都作为双变量存储在内部,因为空间优化很重要,而且不会失去精度。

我想做一些类似的事情:

class Base {
public:
virtual size_t size() = 0;
virtual void addValue () = 0;
virtual void getValue (int index) = 0;
};
class BaseFloat : public Base{
public:
vector<float> data;
void addValue (float d);
float getValue (int index);
size_t size();
}
class BaseInt : public Base{
public:
vector<int> data;
void addValue (int d);
Int getValue (int index);
size_t size();
}
/* other classes for each data type here*/

这不起作用,因为每个函数都有不同的返回类型或参数需求;

然后我有一个类,它为每一行创建正确的对象。

当我需要其他类来处理任何类型的Base时,问题就来了。我在想:

class OtherClass {
public:
void addValue(Base*, double);
}
OtherClass my_class; //whatever
Base* a = new BaseFloat ();
Base* b = new BaseInt();
my_class.addData(a, 5.56); //Uses BaseFloat::addValue
my_class.addData(b, 6);  //Uses BaseInt::addValue
my_class.addData(b, 6.55); //Uses BaseInt::addValue

我希望我能做到这一点,而不添加任何长的"如果不是"条款类似:

void OtherClass::addDataHelper (Base* pointer)
if (subclass(pointer) == float)
//Do BaseFloat* a = pointer;
//Do a->addValue
else if ...

有什么想法吗?

创建OO设计时,需要定义基类的接口,这样所有派生类都可以覆盖虚拟函数,而无需更改签名。例如,对于读取数据,它可以实现为:

class BaseData {
public:
virtual bool addValue( std::istream &in ) = 0;
};
class DataFloat : public BaseData {
virtual bool addValue( std::istream &in ) override
{
float v = 0;
if( not in >> v ) return false;
data_.push_back( v );
return true;
}
private:
std::vector<float> data_;
};
class Factory {
public:
std::unique_ptr<BaseData> create( const std::string &type );
};
std::vector<std::unique_ptr<BaseData>> parsing( std::istream &in, Factory &f )
{
std::vector<std::unique_ptr<BaseData>> v;
std::string str;
while( std::getline( in, str ) ) {
std::istringstream line( str );
std::string type;
if( not in >> type ) continue;
auto pbase = f.create( type );
while( pbase->addValue( in ) );
v.push_back( std::move( pbase ) );
}
return v;
}

当然,这不是完整的代码,但应该足以展示这个想法。因此,对于您的操作,您需要做同样的事情——找到在基类中定义虚拟函数的方法,这样它就可以在每个派生函数中重新实现,而无需更改签名。每个类都有void addValue( int data )void addValue( float data )的方法不是正确的OO设计,会导致ifdynamic_cast级联或类似的方法。

另一个解决方案是将数据保存在std::vector<std::variant<int,float,char,double>>中(列出了所有必要的类型(,并编写适当的访问者来进行数据插入和计算等。互联网上有很多关于如何正确执行这一操作的材料,如果将它们添加到此处,将超出本答案的范围。