| | |
Changing the Access Specifier in Virtual Functions
Please support our C++ advertiser: Intel Parallel Studio Home
![]() |
•
•
Join Date: Jul 2008
Posts: 19
Reputation:
Solved Threads: 0
C++ Syntax (Toggle Plain Text)
class Base { public: virtual void fn(){cout<<"fn base\n";} virtual void myfn(){cout<<"myfn base\n";} }; class Derived : private Base { private: void fn(){cout<<"der\n";} void myfn(){cout<<"myfn Derived\n";} }; int _tmain(int argc, _TCHAR* argv[]){ Derived d; Base *p = &d; //Error: conversion from derived * to base * exists but is inaccessible p->fn(); p->myfn(); }
If i change the pointer initialization to
C++ Syntax (Toggle Plain Text)
Base *p = (Base *)&d;
it works fine.
Please explain ... Thnx
•
•
Join Date: Aug 2008
Posts: 206
Reputation:
Solved Threads: 31
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
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.
Through experimentation, I found that this is also legal--
c++ Syntax (Toggle Plain Text)
#include <iostream> class Base { public: virtual void fn(){std::cout<<"fn base\n" << std::endl;} virtual void myfn(){std::cout<<"myfn base\n" << std::endl;} }; class Derived : private Base { private: void fn(){std::cout<<"der\n" << std::endl;} void myfn(){std::cout<<"myfn Derived\n" << std::endl;} }; int main(){ Derived d; Base *p = reinterpret_cast< Base*>(&d); p->fn(); p->myfn(); return 0; }
Last edited by Alex Edwards; Aug 25th, 2008 at 8:33 am.
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
C++ Syntax (Toggle Plain Text)
Derived d; Base *p = reinterpret_cast< Base*>(&d);
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.
•
•
•
•
> I found that this is also legal--C++ Syntax (Toggle Plain Text)
Derived d; Base *p = reinterpret_cast< Base*>(&d);
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.
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.
>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:
For the sake of argument, assume that this is how an object of Base is represented internally:
And an object of Derived is represented like so:
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:
But Derived now looks like this:
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.
>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)
#include <iostream> class Base { const char *p; public: virtual void foo() { std::cout<<"Base\n"; } }; class Derived: private Base { const char *q; virtual void foo() { std::cout<<"Derived\n"; } }; int main() { Derived d; Base *p = (Base*)&d; p->foo(); }
C++ Syntax (Toggle Plain Text)
Base::{ vptr | p }
C++ Syntax (Toggle Plain Text)
Derived::{ Base::{ vptr | p } | q }
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)
Base::{ vptr | p }
C++ Syntax (Toggle Plain Text)
Derived::{ q | Base::{ vptr | p } }
I'm here to prove you wrong.
•
•
•
•
For the sake of argument, assume that this is how an object of Base is represented internally:
And an object of Derived is represented like so:C++ Syntax (Toggle Plain Text)
Base::{ vptr | p }
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.C++ Syntax (Toggle Plain Text)
Derived::{ Base::{ vptr | p } | q }
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:
But Derived now looks like this:C++ Syntax (Toggle Plain Text)
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.C++ Syntax (Toggle Plain Text)
Derived::{ q | Base::{ vptr | p } }
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.
![]() |
Other Threads in the C++ Forum
- Previous Thread: QS Algorithm Problem
- Next Thread: C++ problem
| Thread Tools | Search this Thread |
api array arrays based beginner binary c++ c/c++ calculator char class classes code compile compiler console conversion count delete deploy desktop directshow dll download dynamic dynamiccharacterarray encryption error file forms fstream function functions game getline givemetehcodez google graph gui homeworkhelp homeworkhelper iamthwee ifstream input int integer java lib linkedlist linker linux list loop looping loops map math matrix memory news number output parameter pointer problem program programming project proxy python random read recursion recursive reference return rpg string strings struct temperature template templates test text text-file tree unix url variable vector video visual visualstudio win32 windows winsock word wordfrequency wxwidgets






