简体   繁体   中英

C++ Inheritance constructor override

I have a piece of code that applies a lot of computations to a set of data. This data is organized in a class, and consists mostly of scalars and arrays of floats and doubles. The problem is that the variables on the class depends on the input file structure, ie, file A may have 10 scalar variables and B may have 20 arrays. How can I create an abstraction to deal with this heterogeneous data?

I thought of creating a class Data and a specific one for each different input, A and B, which inherit from Data. However I've a big problem:

In the code I only want to address the dataset as the Data class, in a

vector<Data> datas;
Data d = new Data();
datas.push_back(d);

and I don't want to do

vector<Data> datas;
Data d = new A();
datas.push_back(d);

but that implies that the parent class will access the child class for the variables, constructors, etc, which I don't now if it's possible (note that the application only reads file A or B, not both in the same execution, I have no problem of setting which at compile time and only add the class A or B to the code)

PS: In the original code, written by non computer scientists, they would create the Data class and and an #include "variables.cxx" in its declaration. It obviously works but should be avoided at all costs...

You need an array of pointers to the base class. This allows vector to work with one type of fixed size (pointer to base class), but that type represents all your objects of different size.

std::vector<base*> datas;
datas.push_back(new derived);

If you have c++11 then vector can manage the memory for you:

std::vector<std::unique_ptr<base>> datas;
datas.push_back(std::make_unique<derived>());

Use dynamic binding in C++ which allow you access functions(except constructor) in child class by pointer of parent type. This is a sample:

class Data
{
public:
    virtual void func() = 0;    
};

class A : public Data
{
public:
    void func();
};

class B : public Data
{
    void func();
};

Then you can process data like this:

vector<Data*> datas;
Data *d = new A();
d->func();//do something, for example read data from files
datas.push_back(d);

Templates

One option, as you said you are happy to choose the type at compile time is to template your code on the data type:

template<typename Data>
void doComputations() {
    std::vector<Data> datas;
    Data d;
    datas.push_back(d);
}

doComputations<A>();

Then you don't need a base Data class just an implicit interface shared by A and B . But this might mean a lot of your code has to be templated which might not be want you want.

Polymorphism

With stack allocated objects

If you want to take advantage of the runtime polymorphic behaviour of a Data base class then you need to store a vector of pointers.

One way of filling the vector would be to have separate vectors that own the A and B and then one vector of Data raw pointers to do the computations on:

std::vector<A> a_datas;
std::vector<B> b_datas;

a_datas.push_back(A{});
a_datas.push_back(A{});
b_datas.push_back(B{});

std::vector<Data*> datas;    
for (auto& a : a_datas)
  datas.push_back(&a);

for (auto& b : b_datas)
  datas.push_back(&b);

doComputations(datas);

With heap allocated objects

Or the more flexible approach is to allocate the objects on the heap and manage them with one vector of smart pointers:

struct Data {
public:
  virtual ~Data(){}
  //...
};

struct A : Data { /* ... */ };
struct B : Data { /* ... */ };

std::unique_ptr<Data> loadData() {
  if ( condition )
    return std::make_unique<A>();
  else
    return std::make_unique<B>();
   }
}

std::vector<std::unique_ptr<Data>> datas;    
datas.push_back(loadData());
datas.push_back(loadData());

doComputations(datas);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM