Skip to main content
gamedev.net
🔒 Locked

inheritance problem

Started by nprz Nov 5, 2004 at 9:02 PM 8 replies 900+ views
Original Post
nprz
nprz
I am not too familiar with inheritance with C++, so I am hoping someone can inform me. I have a base class called symbol and an inherited class called variable_symbol. I tried making a function that returns a symbol pointer but I wanted to use that pointer for my inherited class. How would I program this correctly? Any better approaches would be fine as well.
parser.cpp(108) : error C2440: 'initializing' : cannot convert from 'class symbol *' to 'class variable_symbol *'
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
ajas95
ajas95
are you static_cast<>ing?

I assume you have something like:

variable_symbol* vsym = get_symbol();

where get_symbol() is a method that returns symbol* ?
ga
ga
This works only the other way, you can assign a derived-class pointer to a base class pointer. For the conversion of a base class pointer to the derived class pointer you have to do an explicit cast (and you should be sure that it's really a pointer to this derived class):

variable_symbol *derivedclasspointer = (variable_symbol*)getsymbol();
Visit our homepage: www.rarebyte.de.stGA
nprz
nprz
Ok. I changed it and it worked. Now that I think about it though, I don't think it will run properly because I did create a symbol class and if I try to use it as a derived class it will probably get an error, right?

If I have to create a derived symbol do I have to use make a function specific for that symbol or can I make a generic one and maybe even pass the name of the class?

ajas95
ajas95
you should definitely use static_cast instead of the c cast, which means:
variable_symbol* vsym = (variable_symbol *)get_symbol();  // BADvariable_symbol* vsym = static_cast<variable_symbol *>(get_symbol()); // GOOD!

basically, the c-cast (the bad one) will take whatever memory is there and casts it to the specified type, regardless of whether or not the cast makes any sense. If there is a problem, you get a run-time error which is bad. Using static_cast the compiler checks to see if the types are convertible and if not, generates a compile-time error, which is GOOD. Compile-time errors are easy to fix, run-time errors are hard to fix. Now, in this case it wouldn't have caught the problem, but whatever :-).

Do you need to do different things based on what type of symbol is being created? If not, you can use a templated function to generate the symbol. It's a little more advanced, but not too hard to use.
template <class T>T* get_symbol(){    return new T();}    // then, to use it:void main(){    symbol* psym = get_symbol<symbol>();    variable_symbol* pvar_sym = get_symbol<variable_symbol>();}

so, you can see that whatever you put in the <...>, the compiler generates the function, filling in the 'T' from the template, then calls that. So, no casting is required here, because of the line "T* get_symbol()", returns a pointer to type T*, which when called with becomes essentially "variable_symbol* get_symbol()". So since it's already returning a variable_symbol* you don't need to cast it to one.

It's a little more complicated, like I said, but worth learning.
nprz
nprz
I supposedly learned this years ago, but since I didn't use it extensively then and haven't used it until now I forgot just about everything. Relearning templates took me long enough :)

The static cast seemed to compile so I don't think I will need to use a templated function.

Thanks a bunch and I owe you one :)
iMalc
iMalc
Quote:
Original post by ajas95
basically, the c-cast (the bad one) will take whatever memory is there and casts it to the specified type, regardless of whether or not the cast makes any sense. If there is a problem, you get a run-time error which is bad. Using static_cast the compiler checks to see if the types are convertible and if not, generates a compile-time error, which is GOOD. Compile-time errors are easy to fix, run-time errors are hard to fix. Now, in this case it wouldn't have caught the problem, but whatever :-).
You have to be careful about your wording there. A C-sytle cast never actually fails at run-time or causes a run-time error. It's merely a case of any incorrect behaviour such as casting to the wrong pointer type and writing to memory that you shouldn't, which is what actually causes a run-time error. The same bug is often going to be possible if you use C++ sytle casts.

Don't get me wrong, they do pick up some errors for you at compile time which force you to correct the error before running the program, and you *should* use them over C-style casts. Though almost everyone occasionally does a C-style cast out of laziness, as it's far shorter to type, and some people probably can't spell reinterpret_cast either.
ajas95
ajas95
well, the point of me bringing up the templated function was because it sounded like you were doing something like:
symbol* get_symbol(){    return new symbol;}

and then downcasting that into a variable_symbol, which you were right, that would be really bad. And so it sounded like you were wondering if you were going to have to do something like:
symbol* get_symbol()          { return new symbol; }symbol* get_variable_symbol() { return new variable_symbol; }symbol* get_another_symbol()  { return new another_symbol; }etc...

which would be a big pain in the butt. So that's why I brought up the templated version, you just write it once, then call it with whatever class you want.
Quote:
do I have to use make a function specific for that symbol or can I make a generic one and maybe even pass the name of the class?

The templated function is a way to do just that. It was just a thought, not necessary by any means. But definitely avoid creating a symbol with new, then downcasting to a variable_symbol.
Zahlman
Zahlman
ajas95 has it right.

Basically, inheritance is good for ignoring type information that gets in your way, but it's hard to get that information back; templating is good for keeping type information associated with things, but you can't forget the information when you'd like to be able to for simplicity (thus the templated-ness tends to propagate). So sometimes you need to use both - in your case, have an inheritance relationship between symbols so that calling code can treat them similarly (and be protected from having to know about different kinds of symbols), and use templates for your 'factory methods' so that the symbol module itself can remember what it needs to.

Edit: I use the term "need" loosely, of course. Java programmers have gotten along "just fine" without any kind of templates or genericity for... 6 years, right? Came out in 1998, yeah? And plain old C programmers never had any inheritance or polymorphism availabe to them except pointer-cast polymorphism, and they did some pretty impressive stuff too. But there's always something to be said for using the right tool for the job.
nprz
nprz
Thanks everyone. I implemented the templated function and I think it fixed problems that it was having.

Now I can spend my weekend programming the symbol and symbol table generated for my compiler.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.