473,241 Members | 1,370 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,241 software developers and data experts.

Virtual function pointers (& multiple inheritance?)

Hi all. I'm maintaining a C++ program and I've come across a nasty piece
of code that works, but I just don't understand why. I'm not actually
this part of the program, but I really want to know how and why it works.

I'll post a simplified version of it below and ask my questions
afterwards:

class Base {
void *function_ptr;

public:
Base();
void Initialize();
virtual void Function();
};

Base::Base() {
function_ptr = (void *)&Base::Function;
}

void Base::Initialize() { // should be called from derived constructor
if ( function_ptr != (void *)&Base::Function ) {
/* do something */
}
}

void Base::Function() {
/* some code */
}
class Derived : public virtual Base {
public:
Derived();
virtual void Function();
};

Derived::Derived() {
Initialize();
}

void Derived::Function() {
/* some code */
}
So the derived class overrides the virtual function "Function". Now, when
the derived class calls Initialize (which is non-virtual and defined in
the base), the statements between the curly braces in the if clause
actually get executed. Why does this work? It seems like the base is
setting function_ptr to &Base::Function, but then when it checks it again
in Initialize(), they're no longer equal.

Does this have anything at all to do with the fact that Base is a virtual
base class (ie would this still work if it wasn't a virtual base)? As far
as I knew, virtual bases are used only to prevent multiple copies of the
base class in a multiple inheritance tree, but recent discussion in this
newsgroup has caused me to wonder if there isn't (quite a bit) more to it
than that.

Thanks in advance for any help.

************************************************** ***
Josh Lessard
Master's Student
School of Computer Science
Faculty of Mathematics
University of Waterloo
(519)888-4567 x3400
http://www.cs.uwaterloo.ca
************************************************** ***

Jul 19 '05 #1
11 8050

"Josh Lessard" <jr******@plg2.math.uwaterloo.ca> wrote in message
news:Pi**************************************@plg2 .math.uwaterloo.ca...
function_ptr = (void *)&Base::Function;


This isn't a legitmate cast. No guarantee that a member function pointer can be cast
to void* safely.

What are you trying to do?

Jul 19 '05 #2
Josh Lessard wrote:
...
I'm maintaining a C++ program and I've come across a nasty piece
of code that works, but I just don't understand why. I'm not actually
this part of the program, but I really want to know how and why it works.
...


There's no way to say why it works. Your code is broken (see Ron's
reply) and its behavior is undefined. It might appear to be "working" if
you are lucky and if the weather is right. And tomorrow it might start
to crash consistently.

--
Best regards,
Andrey Tarasevich

Jul 19 '05 #3
Ron Natalie wrote:
"Josh Lessard" <jr******@plg2.math.uwaterloo.ca> wrote in message
news:Pi**************************************@plg2 .math.uwaterloo.ca...

function_ptr = (void *)&Base::Function;

This isn't a legitmate cast. No guarantee that a member function pointer can be cast
to void* safely.

What are you trying to do?


Isn't it obvious?

Someone has exploited a compiler bug to determine whether
Initialize is being called in the constructor of Base or
not. The comment the idiot left says as much.

Jul 19 '05 #4
lilburne wrote:
Ron Natalie wrote:
"Josh Lessard" <jr******@plg2.math.uwaterloo.ca> wrote in message
news:Pi**************************************@plg2 .math.uwaterloo.ca...

function_ptr = (void *)&Base::Function;


This isn't a legitmate cast. No guarantee that a member function
pointer can be cast
to void* safely.

What are you trying to do?


Isn't it obvious?

Someone has exploited a compiler bug to determine whether Initialize is
being called in the constructor of Base or not. The comment the idiot
left says as much.


PS: Your compiler is converting the cast to be an actual
address (BTW this wont compile on some other compilers). In
the constructor of Base this is taken as the actual address
of Base::Function, but in the Initialize method it is
probably being read from the vtable.

Try testing it to see what happens if you call Initialize
from Base constructor or with a class that doesn't override
Function.

Jul 19 '05 #5
> > function_ptr = (void *)&Base::Function;

This isn't a legitmate cast. No guarantee that a member function pointer can be cast
to void* safely.
In this case, it doesn't have to be a "safe cast". The sole purpose of
function_ptr is to compare it to the Base::Function address in the
Initialize() function to see if the function has been overridden in a
derived class.

What it appears to be doing is assigning &Base::Function into function_ptr
in the constructor, and then comparing function_ptr to &Base::Function in
Initialize(). What throws me off kilter is that if Base::Function has
actually been overridden in Derived, they're no longer equal. Why not?
What are you trying to do?


I didn't write the code. I'm extending a project that was written back in
1997. As I said in my earlier post, I'm not touching this code...I'm just
very curious as to why it works.

What the original coder was trying to do was check to see if a derived
class has overridden any of the virtual functions in the base class. His
method works...I'm just at a loss to understand why.

************************************************** ***
Josh Lessard
Master's Student
School of Computer Science
Faculty of Mathematics
University of Waterloo
(519)888-4567 x3400
http://www.cs.uwaterloo.ca
************************************************** ***

Jul 19 '05 #6
> In this case, it doesn't have to be a "safe cast".

The above sentence one of those things I wish I could have taken back just
after I'd sent it. Believe me, I understand what was meant when you said
it wasn't a safe cast. I agree with you...the code is pretty ugly in
places.

All I meant is that nothing is really done with the function pointer,
except to compare it to the address of the function in the base class
(which is where it was taken from anyway).

In any case, it appears that this is working by pure fluke...so I don't
feel so bad that I didn't understand it when I came across it.

Thanks for your replies!

************************************************** ***
Josh Lessard
Master's Student
School of Computer Science
Faculty of Mathematics
University of Waterloo
(519)888-4567 x3400
http://www.cs.uwaterloo.ca
************************************************** ***

Jul 19 '05 #7

"Josh Lessard" <jr******@plg2.math.uwaterloo.ca> wrote in message
news:Pi*************************************@plg2. math.uwaterloo.ca...
function_ptr = (void *)&Base::Function;
This isn't a legitmate cast. No guarantee that a member function pointer can be cast
to void* safely.


In this case, it doesn't have to be a "safe cast".


Safe doesn't enter into it. The compiler doesn't have to even accept it.
No where in the docs for reinterpret_cast does it say you can cast a pointer
to member function to void*. In many implementations they aren't even the
same size.
The sole purpose of
function_ptr is to compare it to the Base::Function address in the
Initialize() function to see if the function has been overridden in a
derived class.
Yes and it only coincidentally works for that. As I said, on many implementations
the cast won't even compile. On others, it may not give you the same prediction.
What the original coder was trying to do was check to see if a derived
class has overridden any of the virtual functions in the base class. His
method works...I'm just at a loss to understand why.

It's pure coincidence. You can't support that code. Once the compiler changes
it may cease to work suddenly. It's dubious that it works at all.
Jul 19 '05 #8

"Josh Lessard" <jr******@plg2.math.uwaterloo.ca> wrote in message
news:Pi*************************************@plg2. math.uwaterloo.ca...

All I meant is that nothing is really done with the function pointer,
except to compare it to the address of the function in the base class
(which is where it was taken from anyway).

You're not even guaranteed that. void* isn't a parking place for an arbitrary
pointer, it's a parking place for an arbitrary object pointer. Pointers to functions
and any sort of pointer to member are not validly converted to void*. Many
compilers will refuse to even attempt such a conversion.
Jul 19 '05 #9
On Thu, 6 Nov 2003, Ron Natalie wrote:
It's pure coincidence. You can't support that code. Once the compiler changes
it may cease to work suddenly. It's dubious that it works at all.


I agree with you 100%. Your answers here have just confirmed my
suspicions, and I don't feel so bad for not understanding what the hell
was going on and why it was "working." :P

Maybe it's time I ordered myself a copy of the C++ standard. I've been
picking up bits and pieces of it by lurking around in this newsgroup, but
it would be nice to be able to confirm things like this for myself.

Thanks again for your time.

************************************************** ***
Josh Lessard
Master's Student
School of Computer Science
Faculty of Mathematics
University of Waterloo
(519)888-4567 x3400
http://www.cs.uwaterloo.ca
************************************************** ***

Jul 19 '05 #10
On Wed, 5 Nov 2003 18:52:58 -0500, Josh Lessard
<jr******@plg2.math.uwaterloo.ca> wrote:
Hi all. I'm maintaining a C++ program and I've come across a nasty piece
of code that works, but I just don't understand why. I'm not actually
this part of the program, but I really want to know how and why it works.

I'll post a simplified version of it below and ask my questions
afterwards:

class Base {
void *function_ptr;

public:
Base();
void Initialize();
virtual void Function();
};

Base::Base() {
function_ptr = (void *)&Base::Function;
}

void Base::Initialize() { // should be called from derived constructor
if ( function_ptr != (void *)&Base::Function ) {
/* do something */
}
}

void Base::Function() {
/* some code */
}
class Derived : public virtual Base {
public:
Derived();
virtual void Function();
};

Derived::Derived() {
Initialize();
}

void Derived::Function() {
/* some code */
}
So the derived class overrides the virtual function "Function". Now,
when
the derived class calls Initialize (which is non-virtual and defined in
the base), the statements between the curly braces in the if clause
actually get executed. Why does this work? It seems like the base is
setting function_ptr to &Base::Function, but then when it checks it again
in Initialize(), they're no longer equal.
Expression &Base::Function maybe evaluated through virtual table , in this
case , when Initialized is called from Derived &Base::Function will return
pointer related to overriden Function.

This all is not regulated in the standard. Proper way to store pointers to
member function is void (Base::*ptr)() type not a void * type.

You may try to replace void * by the above and try again.


Does this have anything at all to do with the fact that Base is a virtual
base class (ie would this still work if it wasn't a virtual base)? As
far
as I knew, virtual bases are used only to prevent multiple copies of the
base class in a multiple inheritance tree, but recent discussion in this
newsgroup has caused me to wonder if there isn't (quite a bit) more to it
than that.

Thanks in advance for any help.

************************************************** ***
Josh Lessard
Master's Student
School of Computer Science
Faculty of Mathematics
University of Waterloo
(519)888-4567 x3400
http://www.cs.uwaterloo.ca
************************************************** ***


--
grzegorz
Jul 19 '05 #11
Grzegorz Sakrejda wrote:
...
Expression &Base::Function maybe evaluated through virtual table , in this
case , when Initialized is called from Derived &Base::Function will return
pointer related to overriden Function.

This all is not regulated in the standard. Proper way to store pointers to
member function is void (Base::*ptr)() type not a void * type.

You may try to replace void * by the above and try again.
...


In general case this won't make much of a difference. When a pointer
that points to a virtual function is involved in equality comparison,
the result is unspecified.

--
Best regards,
Andrey Tarasevich

Jul 19 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Kapil Khosla | last post by:
Dear all, I am trying to underlying implementation of virtual functions in C++. The way I understand polymorphism is class Base { public: virtual int func(); };
4
by: vijay | last post by:
I have a doubt with size of classed with virtual functions I have declared A,A1,A2 ,B , C, D some classes with no varaibles but a vitual function each, The size of A is as expected 4 bytes with...
4
by: Sat | last post by:
Hi, I have a simplified version of a problem that I am facing (hope I haven't oversimplified it). This code doesn't work now and I want to find how I can make it work. Can I call the derived...
18
by: nenad | last post by:
Wouldn't it be nice if we could do something like this: class Funky{ public: auto virtual void doStuff(){ // dostuff } };
4
by: JKop | last post by:
I'm starting to think that whenever you derive one class from another, that you should use virtual inheritance *all* the time, unless you have an explicit reason not to. I'm even thinking that...
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
7
by: alex.mizrahi | last post by:
helo i'm going to use pointers to member function with virtual inheritance in following way: struct base { public: typedef void (base::*fun_t)(void); int i; void call(fun_t f) {
3
by: kikazaru | last post by:
Is it possible to return covariant types for virtual methods inherited from a base class using virtual inheritance? I've constructed an example below, which has the following structure: Shape...
23
by: Dave Rahardja | last post by:
Since C++ is missing the "interface" concept present in Java, I've been using the following pattern to simulate its behavior: class Interface0 { public: virtual void fn0() = 0; };
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.