I'm newish to c++ and am trying to modify an existing c program that has been partially converted to c++. I want to create a derived class with some extra data, but have been trying to figure out the best way to do it and came across this unexpected (for me) behaviour. The simplified code here reproduces it. The existing program uses the first instantiation method (X). Can someone help me understand what is going on? My intention is to minimise changes to the Base class but allow Derived to expose independent extra data (i.e., c), with this instantiation approach. In addition, can anyone suggest the simplest virtual approach?
X defined as Base and allocated as Derived.
X->info: a = 10
X->info: b = 2
X->info: c = 3
X->a = 10
X->b = 2
X->c = 0
Y defined as Base and allocated as Derived.
Y->info: a = 10
Y->info: b = 2
Y->info: c = 3
Y->a = 980379246
Y->b = 32
Y->c = 3
You have declared the member variables {a, b, c} in both Base and Derived. You probably want {a, b} in Base, and {c} in Derived. Remove the rest!
Note that after you do this, the code will not compile, because Base doesn't have a member named "c". This is correct. Fix it by removing line 138. You will still see the value of "c" when you call X->info();
Yeh, however I want to access c directly (i.e. X->c). Like you say, c was included in Base because the compiler insisted upon it :)
I can get around this by turning Base into an abstract class to retrieve private data in Derived (below), which works but is only practical for a small number of Derived classes. The program I'm trying to modify, has Base with a whole bunch of Derived's, and the abstract approach means I would have to go through all existing Derived's and add the retriever functions for their private data, imposing this burden on all future Derived additions. I'm starting to see how the existing set up is pretty poor and am looking at how templates can help me more elegantly arrange things.
By the way, another approach I tried was a downcast using static_cast. This works, but I ran into a limitation (potentially me). I have a function which accepts a Base class pointer that points to one of a dozen or so possible Derived class instances, but the function only wants to perform work if Derived is one of three types (the type index is in Base). Remember, I'm trying to work with an existing code structure here. Downcasting works but if I have branching statements:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int my_function( Base &data, double foo )
{
if (data.type_index == DERIVED_TYPE_1){
DerivedType1 *my_data = static_cast<DerivedType1*>(data);
<work1>
}
if (data.type_index == DERIVED_TYPE_2){
DerivedType2 *my_data = static_cast<DerivedType2*>(data);
<work2>
}
if (data.type_index == DERIVED_TYPE_1){
DerivedType3 *my_data = static_cast<DerivedType3*>(data);
<work3>
}
<work0>
return result;
}
Then the down-cast pointers *my_data only have scope within the if statements and to do <work0> on them I'd need to turn <work0> into another function, apparently. I suppose maybe there is a way to assign *my_data dynamically on the heap, but I don't know how.
To be more specific, in the code below, unblanking the DoWork2 line yields " error: ‘newdata’ was not declared in this scope" on compile . It would be a _whole_ lot easier if I could just get newdata out of the if scope, rather than trying to be a hero with templates and someone elses code. Can I just do some juggling of pointers or something?
int DoWork( Base *data )
{
if ( data->a == 10 )
{
Derived *newdata = static_cast<Derived*>(data);
cout << "DoWork1: c = " << newdata->c << endl;
}
if ( data->a == 11 )
{
Derived2 *newdata = static_cast<Derived2*>(data);
cout << "DoWork1: c = " << newdata->c << endl;
}
if ( data->a == 12 )
{
Derived3 *newdata = static_cast<Derived3*>(data);
cout << "DoWork1: c = " << newdata->c << endl;
}
cout << "DoWork2: c = " << newdata->c << endl;
return 0;
}
All three Derived types have a data member named c that DoWork2 wants to access. If DoWork2 was bundled into another function that was called within each if statement, I suppose it would need to be a template function, but is there another way just to somehow wrangle the pointer?
You're trying to do things with inheritance that doesn't make sense. If some derived classes have a common property ("c"), then maybe they should have a common base class that defines this property.
It's not possible to give you any better advice without having the complete picture about your design, because this is definitely a design question. Although you're trying to turn it into an implementation issue.
The things you're trying to do can't be done, and they can't be done for a reason. It's just not how it works.
Thanks, yeh I totally don't like using hacks like casting etc, but I got it working putting calls to a single virtual function in the "DoWork1" lines. In this case I can't/don't want to redesign the bodgy code. But I think I understand what you're saying about design v implementation. Design seems to be much more important in c++ than c.