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();
}

in the code above, I get an error as mentioned above. Why ?
If i change the pointer initialization to

Base *p = (Base *)&d;

it works fine.

Please explain ... Thnx

Recommended Answers

All 6 Replies

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.

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

#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;
}
Derived d;
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.

commented: My apologies for an ignorant response. +3
Derived d;
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.

>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:

#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();
}

For the sake of argument, assume that this is how an object of Base is represented internally:

Base::{ vptr | p }

And an object of Derived is represented like so:

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:

Base::{ vptr | p }

But Derived now looks like this:

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.

commented: Thanks for a very detailed explanation on data mappings within objects, Professor =) +3

For the sake of argument, assume that this is how an object of Base is represented internally:

Base::{ vptr | p }

And an object of Derived is represented like so:

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:

Base::{ vptr | p }

But Derived now looks like this:

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.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.