Changing the Access Specifier in Virtual Functions

Please support our C++ advertiser: Intel Parallel Studio Home
Reply

Join Date: Jul 2008
Posts: 19
Reputation: kneiel is an unknown quantity at this point 
Solved Threads: 0
kneiel kneiel is offline Offline
Newbie Poster

Changing the Access Specifier in Virtual Functions

 
0
  #1
Aug 25th, 2008
  1. class Base
  2. {
  3. public:
  4. virtual void fn(){cout<<"fn base\n";}
  5. virtual void myfn(){cout<<"myfn base\n";}
  6. };
  7.  
  8. class Derived : private Base
  9. {
  10. private:
  11. void fn(){cout<<"der\n";}
  12. void myfn(){cout<<"myfn Derived\n";}
  13. };
  14.  
  15. int _tmain(int argc, _TCHAR* argv[]){
  16. Derived d;
  17. Base *p = &d; //Error: conversion from derived * to base * exists but is inaccessible
  18. p->fn();
  19. p->myfn();
  20. }
in the code above, I get an error as mentioned above. Why ?
If i change the pointer initialization to
  1. Base *p = (Base *)&d;

it works fine.

Please explain ... Thnx
Reply With Quote Quick reply to this message  
Join Date: Aug 2008
Posts: 206
Reputation: grumpier has a spectacular aura about grumpier has a spectacular aura about 
Solved Threads: 31
grumpier grumpier is offline Offline
Posting Whiz in Training

Re: Changing the Access Specifier in Virtual Functions

 
0
  #2
Aug 25th, 2008
The reason is that Base is a private base class of Derived. Implicit conversion from "pointer to Derived" to a "pointer to Base" relies on public inheritance. Code using Derived (i.e. your _tmain() function does not have access to private members or bases - that is what "private" means.

Your explicit conversion Base *p = (Base *)&d; just forces the conversion to happen. It would also force the issue if Derived did not inherit from Base at all.
Last edited by grumpier; Aug 25th, 2008 at 6:56 am.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 973
Reputation: Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough 
Solved Threads: 107
Alex Edwards's Avatar
Alex Edwards Alex Edwards is offline Offline
Posting Shark

Re: Changing the Access Specifier in Virtual Functions

 
0
  #3
Aug 25th, 2008
Through experimentation, I found that this is also legal--

  1. #include <iostream>
  2.  
  3. class Base
  4. {
  5. public:
  6. virtual void fn(){std::cout<<"fn base\n" << std::endl;}
  7. virtual void myfn(){std::cout<<"myfn base\n" << std::endl;}
  8. };
  9.  
  10. class Derived : private Base
  11. {
  12. private:
  13. void fn(){std::cout<<"der\n" << std::endl;}
  14. void myfn(){std::cout<<"myfn Derived\n" << std::endl;}
  15. };
  16.  
  17. int main(){
  18. Derived d;
  19. Base *p = reinterpret_cast< Base*>(&d);
  20. p->fn();
  21. p->myfn();
  22. return 0;
  23. }
Last edited by Alex Edwards; Aug 25th, 2008 at 8:33 am.
Reply With Quote Quick reply to this message  
Join Date: Dec 2006
Posts: 1,089
Reputation: vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all vijayan121 is a name known to all 
Solved Threads: 164
vijayan121 vijayan121 is offline Offline
Veteran Poster

Re: Changing the Access Specifier in Virtual Functions

 
1
  #4
Aug 25th, 2008
  1. Derived d;
  2. Base *p = reinterpret_cast< Base*>(&d);
> I found that this is also legal--

it will compile.
it will work correctly if and only if the anonymous base class sub-object is at an offset of zero in the derived class object.

do not get lulled into a false sense of security. a reinterpret_cast is a C++ cast. but that does not mean that it gives you any additional protection regarding correctness compared to a C style cast, or the union technique that you posted in another thread. for a reinterpret_cast too, you need to know precisely what you are doing. and as a programmer, you have to take responsibility for its correctness.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 973
Reputation: Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough 
Solved Threads: 107
Alex Edwards's Avatar
Alex Edwards Alex Edwards is offline Offline
Posting Shark

Re: Changing the Access Specifier in Virtual Functions

 
0
  #5
Aug 25th, 2008
Originally Posted by vijayan121 View Post
  1. Derived d;
  2. Base *p = reinterpret_cast< Base*>(&d);
> I found that this is also legal--

it will compile.
it will work correctly if and only if the anonymous base class sub-object is at an offset of zero in the derived class object.

do not get lulled into a false sense of security. a reinterpret_cast is a C++ cast. but that does not mean that it gives you any additional protection regarding correctness compared to a C style cast, or the union technique that you posted in another thread. for a reinterpret_cast too, you need to know precisely what you are doing. and as a programmer, you have to take responsibility for its correctness.
Yes I understand that. I ended up having to do some research on why the cast the OP mentioned was legal, and I admit I still do not understand.

Notice that my post states through experimentation, meaning that I was merely trying to see how the (Base*) cast might be interpreted by the compiler, though I admit I did forget that ( Base* ) is a C-style cast and that I do not understand the way the compiler interprets it.
Reply With Quote Quick reply to this message  
Join Date: Sep 2004
Posts: 7,734
Reputation: Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute Narue has a reputation beyond repute 
Solved Threads: 738
Team Colleague
Narue's Avatar
Narue Narue is offline Offline
Code Goddess

Re: Changing the Access Specifier in Virtual Functions

 
2
  #6
Aug 25th, 2008
>I ended up having to do some research on why the cast the
>OP mentioned was legal, and I admit I still do not understand.
Put simply, the cast is an "I know what I'm doing" switch that turns off the safety net. In this case, and on the OP's implementation, it happened to work out.

>I did forget that ( Base* ) is a C-style cast and that I
>do not understand the way the compiler interprets it.
The cast says

"Here is an address. Pretend the memory at that address represents this type"

Since Base and Derived don't have any data, there's a very good chance that the object mappings will overlay perfectly, and accessing d's virtual pointer through a pointer to Base will produce the expected behavior. But let's pretend that Base and Derived have data:
  1. #include <iostream>
  2.  
  3. class Base {
  4. const char *p;
  5. public:
  6. virtual void foo() { std::cout<<"Base\n"; }
  7. };
  8.  
  9. class Derived: private Base {
  10. const char *q;
  11.  
  12. virtual void foo() { std::cout<<"Derived\n"; }
  13. };
  14.  
  15. int main()
  16. {
  17. Derived d;
  18. Base *p = (Base*)&d;
  19.  
  20. p->foo();
  21. }
For the sake of argument, assume that this is how an object of Base is represented internally:
  1. Base::{ vptr | p }
And an object of Derived is represented like so:
  1. Derived::{ Base::{ vptr | p } | q }
It's fair to say the cast will work, and the result will be polymorphic because taking memory originally mapped as Derived and treating it like it's Base will have the same net effect. The vptr is in the same place (but points to a different table), so accessing foo through p is safe and meaningful.

Now let's move on to a different implementation that places the base class subobject at the end of an object. Base would still look like this:
  1. Base::{ vptr | p }
But Derived now looks like this:
  1. Derived::{ q | Base::{ vptr | p } }
So what happens when memory originally mapped as Derived is accessed through a pointer to Base that assumes the offset of vptr is where q actually resides? q isn't a pointer to a virtual table, so any number of things could happen, but polymorphic behavior is unlikely.
I'm here to prove you wrong.
Reply With Quote Quick reply to this message  
Join Date: Jun 2008
Posts: 973
Reputation: Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough 
Solved Threads: 107
Alex Edwards's Avatar
Alex Edwards Alex Edwards is offline Offline
Posting Shark

Re: Changing the Access Specifier in Virtual Functions

 
0
  #7
Aug 25th, 2008
Originally Posted by Narue View Post
For the sake of argument, assume that this is how an object of Base is represented internally:
  1. Base::{ vptr | p }
And an object of Derived is represented like so:
  1. Derived::{ Base::{ vptr | p } | q }
It's fair to say the cast will work, and the result will be polymorphic because taking memory originally mapped as Derived and treating it like it's Base will have the same net effect. The vptr is in the same place (but points to a different table), so accessing foo through p is safe and meaningful.

Now let's move on to a different implementation that places the base class subobject at the end of an object. Base would still look like this:
  1. Base::{ vptr | p }
But Derived now looks like this:
  1. Derived::{ q | Base::{ vptr | p } }
So what happens when memory originally mapped as Derived is accessed through a pointer to Base that assumes the offset of vptr is where q actually resides? q isn't a pointer to a virtual table, so any number of things could happen, but polymorphic behavior is unlikely.
It's time for me to purchase the C++ Object Model to better understand Objects and how the data is mapped so I'll avoid blind casts that will cause problems.

Thank you Professor.

@vijayan121 - Sorry for the ignorant reply. When I don't understand something and there's no obvious risk in front of me I tend to do experimentation and research later. If it were a risky situation then I would commit that process in reverse.
Last edited by Alex Edwards; Aug 25th, 2008 at 3:52 pm.
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Other Threads in the C++ Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC