943,721 Members | Top Members by Rank

Ad:
  • C++ Discussion Thread
  • Unsolved
  • Views: 1371
  • C++ RSS
Aug 25th, 2008
0

Changing the Access Specifier in Virtual Functions

Expand Post »
C++ Syntax (Toggle Plain Text)
  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
C++ Syntax (Toggle Plain Text)
  1. Base *p = (Base *)&d;

it works fine.

Please explain ... Thnx
Reputation Points: 10
Solved Threads: 0
Newbie Poster
kneiel is offline Offline
19 posts
since Jul 2008
Aug 25th, 2008
0

Re: Changing the Access Specifier in Virtual Functions

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.
Reputation Points: 193
Solved Threads: 32
Posting Whiz in Training
grumpier is offline Offline
206 posts
since Aug 2008
Aug 25th, 2008
0

Re: Changing the Access Specifier in Virtual Functions

Through experimentation, I found that this is also legal--

c++ Syntax (Toggle Plain Text)
  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.
Reputation Points: 392
Solved Threads: 108
Posting Shark
Alex Edwards is offline Offline
971 posts
since Jun 2008
Aug 25th, 2008
1

Re: Changing the Access Specifier in Virtual Functions

C++ Syntax (Toggle Plain Text)
  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.
Reputation Points: 1159
Solved Threads: 285
Posting Virtuoso
vijayan121 is offline Offline
1,606 posts
since Dec 2006
Aug 25th, 2008
0

Re: Changing the Access Specifier in Virtual Functions

Click to Expand / Collapse  Quote originally posted by vijayan121 ...
C++ Syntax (Toggle Plain Text)
  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.
Reputation Points: 392
Solved Threads: 108
Posting Shark
Alex Edwards is offline Offline
971 posts
since Jun 2008
Aug 25th, 2008
2

Re: Changing the Access Specifier in Virtual Functions

>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:
C++ Syntax (Toggle Plain Text)
  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:
C++ Syntax (Toggle Plain Text)
  1. Base::{ vptr | p }
And an object of Derived is represented like so:
C++ Syntax (Toggle Plain Text)
  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:
C++ Syntax (Toggle Plain Text)
  1. Base::{ vptr | p }
But Derived now looks like this:
C++ Syntax (Toggle Plain Text)
  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.
Administrator
Reputation Points: 6442
Solved Threads: 1393
Bad Cop
Narue is offline Offline
11,807 posts
since Sep 2004
Aug 25th, 2008
0

Re: Changing the Access Specifier in Virtual Functions

Click to Expand / Collapse  Quote originally posted by Narue ...
For the sake of argument, assume that this is how an object of Base is represented internally:
C++ Syntax (Toggle Plain Text)
  1. Base::{ vptr | p }
And an object of Derived is represented like so:
C++ Syntax (Toggle Plain Text)
  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:
C++ Syntax (Toggle Plain Text)
  1. Base::{ vptr | p }
But Derived now looks like this:
C++ Syntax (Toggle Plain Text)
  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.
Reputation Points: 392
Solved Threads: 108
Posting Shark
Alex Edwards is offline Offline
971 posts
since Jun 2008

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C++ Forum Timeline: QS Algorithm Problem
Next Thread in C++ Forum Timeline: C++ problem





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC