-3

I have this block of code:

struct Road_Primitive {
public:
    Road_GPU_Point A;
    Road_GPU_Point B;
    Road_GPU_Point C;
};

struct Road_Primitive_4P : public Road_Primitive {
    Road_GPU_Point D;
};

struct Road_Primitive_3P : public Road_Primitive{
};

And in one of my classes I have a Road_Primitive*, which is initialized with either new Road_Primitive_4P or new Road_Primitive_3P, depending on other factors.

However, this section of code gives me an "class Road_Primitive has no member D":

Road_Primitive* pmtv_Prospect = new Road_Primitive_4P;
pmtv_Prospect->D.X = pch_Rightmost->GPU_Primitive->B.X;

However, if I declare Road_Primitve with protected members, the error turns into something like: "Member B is inaccesible"

Any suggestions?

RatkinHHK
  • 27
  • 1
  • 4
  • you have a wrong abstraction here; `D` is 4P-only. `Road_Primitive` doesn't know about it. Either use `Road_Primitive_4P* pmtv_Prospect = new Road_Primitive_4P;` instead of `Road_Primitive* pmtv_Prospect = new Road_Primitive_4P;`, or re-think your abstraction here (virtual methods etc). The error is self-explanatory: `class Road_Primitive has no member D`, that's just it. If you cast an object to a supertype, you essentially "give up" all of the subtype extension details. –  Apr 01 '16 at 20:23
  • But then how do I solve my problem? I do not know if an instance of class "X" will have a **3P** or **4P** struct. I want to decide that at run time, depending on other factors. – RatkinHHK Apr 01 '16 at 20:27
  • 2
    if you don't know if it's 3P or 4P, how do you know it would have `->D` member? hint: you can't know that, so you can't use that. Design the class with either virtual methods to handle this (better solution) or type checking (worse solution). Also: if you want an actual solution, provide an actual problem with context. Without the surrounding setting (code, goals etc.) and a specific description of what *actually* you want to achieve and why, nobody can really help you. –  Apr 01 '16 at 20:29
  • I have found a workaround without using inheritance. But now it is more clear to me why it did not work in the first place. Thanks. – RatkinHHK Apr 01 '16 at 20:34
  • You would get better answers if you stated, as precisely as possible, what you're trying to do. Is your question "If I have a variable of type `Road_Primitive*` that I know for a fact actually points to a `Road_Primitive_4P`, how do I get the value of `D`?" – David Schwartz Apr 01 '16 at 20:35

2 Answers2

0

Well, class Road_Primitive hasn't any member D. Every expression is interpreted in light of the declared types of all its sub-expressions, as evaluated by the compiler. The fact that pmtv_Prospect currently points to a Road_Primitive_4P at some point during the execution doesn't factor in -- if you access that Road_Primitive_4P via a Road_Primitive * then you have access only to those members declared by class Road_Primitive.

If you want to be able to access Road_Primitive_4P.D, then you must do so via a value of (declared) type Road_Primitive_4P. Thus, you could write

Road_Primitive_4P* pmtv_Prospect = new Road_Primitive_4P;
pmtv_Prospect->D.X = pch_Rightmost->GPU_Primitive->B.X;

Of course, in that case you cannot assign pmtv_Prospect to point to a Road_Primitive_3P, but that's really the whole point. If you could make it point to a Road_Primitive_3P, which has no member D, then it would not be safe to access the referent's D.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

struct Road_Primitive, does not, in fact, have a member called D. Although you're allocating a Road_Primitive_4P, you're storing it in a pointer to type Road_Primitive, so when you access (pmtv_Prospect) you only have access to the fields in Road_Primitive.

Usually when you store instances of child classes as parent classes, you want polymorphism, and virtual methods, or else some other means of telling which of those child classes the pointer really points to.

In order to use "dynamic_cast" as Gaurav suggested, your structs or classes need to have at least one virtual method. Starting with a destructor is probably a good idea:

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

And one in each child class:

struct Road_Primitive_4P: public Road_Primitive {
public:
    virtual ~Road_Primitive_4P() {};

Then if you have a Road_Primitive pointer and want to access members of it that are only accessible in Road_Primitive_4P you can use dynamic_cast:

Road_Primitive_4P* temp = dynamic_cast<Road_Primitive_4P*>(pmtv_Prospect);
if (temp)  // then do something with temp->D

dynamic_cast() will return 0 if the object doesn't match the type you're trying to cast to.

Also bear in mind that this style of polymorphism is generally considered bad style because it tends to centralize behaviors that are specific to the different types. Using virtual methods is usually preferable because the behavior specific to each type is stored in the definition of that type.

tetsujin
  • 96
  • 6
  • I wouldn't talk about `dynamic_cast` to OP here at all, since he'll probably just get the idea stuck in his head and just keep casting everything everywhere... I sincerely miss a virtual method solution in your answer - you mentioned it, yet you haven't provided it. –  Apr 01 '16 at 20:40