Inheritance

  • Thread starter =?ISO-8859-2?Q?=AEeljko_Kne=BEevi=E6?=
  • Start date
?

=?ISO-8859-2?Q?=AEeljko_Kne=BEevi=E6?=

Hi,
Given the following code snippet:

======================================================
#include <iostream>

class base {
public:
void f() { std::cout<< "void base::f();" << std::endl; }
};

class derived: public base {
public:
void f() { std::cout << "void derived::f();" << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
return EXIT_SUCCESS;
}
======================================================

The output is: void derived::f();

I'd like someone to confirm me that the output should be treated as
unpredictable because of the second line in main(). I'm casting the base
class into the derived one and there is no guarantee this will work. Am
I mistaken?


®eljko Kne¾eviæ
 
L

Larry I Smith

®eljko Kne¾eviæ said:
Hi,
Given the following code snippet:

======================================================
#include <iostream>

class base {
public:
void f() { std::cout<< "void base::f();" << std::endl; }
};

class derived: public base {
public:
void f() { std::cout << "void derived::f();" << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
return EXIT_SUCCESS;
}
======================================================

The output is: void derived::f();

I'd like someone to confirm me that the output should be treated as
unpredictable because of the second line in main(). I'm casting the base
class into the derived one and there is no guarantee this will work. Am
I mistaken?


®eljko Kne¾eviæ

Make f() 'virtual' in both 'base' and 'derived', e.g.:

virtual void f() {...};

Actually, f() doe not have to be virtual in 'derived', but
if you ever have another class that inherits from 'derived'
('derivedDerived' perhaps), then derived::f() should be
virtual to ensure you can access the f() in all three classes
via the appropriate cast.

Regards,
Larry
 
?

=?ISO-8859-2?Q?=AEeljko_Kne=BEevi=E6?=

Larry said:
Make f() 'virtual' in both 'base' and 'derived', e.g.:

virtual void f() {...};

Actually, f() doe not have to be virtual in 'derived', but
if you ever have another class that inherits from 'derived'
('derivedDerived' perhaps), then derived::f() should be
virtual to ensure you can access the f() in all three classes
via the appropriate cast.

Thank you for your reply.

Unfortunately this is not the answer I wanted. :)

I can do this (taken that: class derived: public base {...}):
base b;
derived d;
b=d;

The thing I do not understand is why (and how) I'am able to do perform
the cast d=b? (the second line in the original post's main() function)

Taken that you are right, what sholud be the output of the following code:

================================
#include <iostream>

class base {
int i;
public:
base(): i(1) { }
void f() { std::cout<< "i = " << i << std::endl; }
};

class derived: public base {
int i;
public:
derived(): i(2) { }
void f() { std::cout << "i = " << i << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
system("pause");
return 0;
}
================================
(I get 0)

I agree this is not a nice way to write a code, but I'm curious.


®eljko Kne¾eviæ
 
?

=?ISO-8859-2?Q?=AEeljko_Kne=BEevi=E6?=

®eljko Kne¾eviæ said:
The thing I do not understand is why (and how) I'am able to do perform
"...able to perform...", without "do". :) My mistake.

®eljko
 
H

Howard

Larry I Smith said:
Make f() 'virtual' in both 'base' and 'derived', e.g.:

virtual void f() {...};

Actually, f() doe not have to be virtual in 'derived', but
if you ever have another class that inherits from 'derived'
('derivedDerived' perhaps), then derived::f() should be
virtual to ensure you can access the f() in all three classes
via the appropriate cast.

That's not needed. If the base class defines the function as virtual, then
it's virtual throughout all descendant classes. (But I put the virtual
keyword there anyway, just so I don't have to hunt for the base class to see
what's virtual and what isn't.)

In any case, it's not relevant to the OP's problem, which is the fact that
he's created a base class object and is treating it as a derived class
object. If the line of code had been

base* b = new derived;

then inheritance would have come into play (and then no cast would not have
been needed, assuming that f were virtual). But he is right that it's
undefined behavior in his case, because he's simply telling the compiler to
treat one object as another, not taking advantage of polymorphism.

-Howard
 
V

Victor Bazarov

®eljko Kne¾eviæ said:
Given the following code snippet:

======================================================
#include <iostream>

class base {
public:
void f() { std::cout<< "void base::f();" << std::endl; }
};

class derived: public base {
public:
void f() { std::cout << "void derived::f();" << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
return EXIT_SUCCESS;
}
======================================================

The output is: void derived::f();

I'd like someone to confirm me that the output should be treated as
unpredictable because of the second line in main(). I'm casting the base
class into the derived one and there is no guarantee this will work. Am
I mistaken?

No, you're not. The result is only defined if the pointer ('b') you pass
to the static_cast is a pointer to a 'base' subobject of an object that
was originally created as a 'derived' object.

In your case, 'b' is a pointer to a 'base' _complete_ object and not part
of a 'derived' object, so the static_cast's result is *undefined*.

V
 
V

Victor Bazarov

®eljko Kne¾eviæ said:
[...]
I can do this (taken that: class derived: public base {...}):
base b;
derived d;
b=d;

The thing I do not understand is why (and how) I'am able to do perform
the cast d=b? (the second line in the original post's main() function)

You *cannot* perform

d=b

you can only perform

b=d

which actually extracts the 'base' subobject from 'd' and assigns 'b' from
it (by making a copy).

V
 
L

Larry I Smith

®eljko Kne¾eviæ said:
Thank you for your reply.

Unfortunately this is not the answer I wanted. :)

I can do this (taken that: class derived: public base {...}):
base b;
derived d;
b=d;

The thing I do not understand is why (and how) I'am able to do perform
the cast d=b? (the second line in the original post's main() function)

Taken that you are right, what sholud be the output of the following code:

================================
#include <iostream>

class base {
int i;
public:
base(): i(1) { }
void f() { std::cout<< "i = " << i << std::endl; }
};

class derived: public base {
int i;
public:
derived(): i(2) { }
void f() { std::cout << "i = " << i << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();

Oops, I totally missed that your original post was trying
to convert a 'base' to a 'derived'; my brain was thinking
about casting a 'derived' to a 'base' (sorry).
Your 'b' is a 'base' (not a 'derived'). You are trying
to cast it to a 'derived' (something that is is not).
The results are 'undefined'. On my machine your code outputs
"i = 1".

If 'b' was a 'derived', then you could cast it to a 'base',
as long as f() was declared 'virtual'.
system("pause");
return 0;
}
================================
(I get 0)

I agree this is not a nice way to write a code, but I'm curious.


®eljko Kne¾eviæ

Regards,
Larry
 
L

Larry I Smith

®eljko Kne¾eviæ said:
Hi,
Given the following code snippet:

======================================================
#include <iostream>

class base {
public:
void f() { std::cout<< "void base::f();" << std::endl; }
};

class derived: public base {
public:
void f() { std::cout << "void derived::f();" << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
return EXIT_SUCCESS;
}
======================================================

The output is: void derived::f();

I'd like someone to confirm me that the output should be treated as
unpredictable because of the second line in main(). I'm casting the base
class into the derived one and there is no guarantee this will work. Am
I mistaken?


®eljko Kne¾eviæ

Read this; it explains the problem very well:

http://www.icce.rug.nl/documents/cplusplus/cplusplus14.html

Regards,
Larry
 
L

Larry I Smith

®eljko Kne¾eviæ said:
Hi,
Given the following code snippet:

======================================================
#include <iostream>

class base {
public:
void f() { std::cout<< "void base::f();" << std::endl; }
};

class derived: public base {
public:
void f() { std::cout << "void derived::f();" << std::endl; }
};

int main() {
base *b = new base;
static_cast<derived*>(b)->f();
return EXIT_SUCCESS;
}
======================================================

The output is: void derived::f();

I'd like someone to confirm me that the output should be treated as
unpredictable because of the second line in main(). I'm casting the base
class into the derived one and there is no guarantee this will work. Am
I mistaken?


®eljko Kne¾eviæ

Maybe this will help see how inheritance and virtual functions interact:

#include <iostream>

class base {
int i;
public:
base() : i(1) {}
void f() { std::cout<< " base::f(), i = " << i << std::endl; }
};

class derived: public base {
int i;
public:
derived() : i(2) {}
void f() { std::cout << " derived::f(), i = " << i << std::endl; }
};

class basev {
int i;
public:
basev() : i(3) {}
virtual void f() { std::cout<< " basev::f(), i = " << i
<< std::endl; }
};

class derivedv : public basev {
int i;
public:
derivedv() : i(4) {}
virtual void f() { std::cout << " derivedv::f(), i = " << i
<< std::endl; }
};


int main() {
base *b = new base;
basev *bv = new basev;
derived *d = new derived;
derivedv *dv = new derivedv;

std::cout << "calling f() thru the original class ptrs" << std::endl;
b->f();
d->f();
bv->f();
dv->f();

std::cout << std::endl << "undefined behavior: ";
std::cout << "'static_cast<derived*>(b)->f()'" << std::endl;
static_cast<derived*>(b)->f();

std::cout << std::endl;
std::cout << "1) 'b = d', 2) 'b->f()'" << std::endl;
b = d;
b->f();

std::cout << std::endl;
std::cout << "1) 'bv = dv', 2) 'bv->f()', 3) 'bv->basev::f()'"
<< std::endl;
bv = dv;
bv->f();
bv->basev::f();

return EXIT_SUCCESS;
}

See the following ling for a very good overview on this subject:

http://www.icce.rug.nl/documents/cplusplus/cplusplus14.html

Regards,
Larry
 
?

=?ISO-8859-2?Q?=AEeljko_Kne=BEevi=E6?=

Larry I Smith wrote:
[...]

Thank you for your reply, code example and the link provided, and thank
Victor for his reply as well.

I'm familiarized with inheritance and virtual paradigm and know why I
can assign b=d and what happens then. I thought the d=b assignment would
result in undefined behavior, but compiler did not confirm that so I
asked the question here. Now I have a confirmation. Topic closed. :)


®eljko Kne¾eviæ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,667
Latest member
DaniloB294

Latest Threads

Top