I've a code as follows -
#include <iostream>
#include <string>
class A{
int a;
public: virtual void sayHello(){ std::cout << "Hello\n"; }
};
class B : private A{
std::string name;
public:
B(std::string _n): name(_n){}
void sayName(){std::cout << name << "says hello\n";}
void sayHello(){sayName();}
};
int main() {
A *ptr = new B("c++");
ptr->sayHello();
return 0;
}
which produces the following compiler output -
Error:
prog.cpp: In function 'int main()': prog.cpp:20:22: error: 'A' is an inaccessible base of 'B' A *ptr = new B("c++"); ^
As previously answered - here, here & here, I know how to solve this issue. By using public
inheritence instead of private
or protected
.
But if I really really want to hide some interface behind the base class, isn't there some other way to do this? Or is it impossible to do so according to c++ lang specification.
If you want polymorphic pointer conversion to work outside the class, then the inheritance must be public. There is no way to work around that.
You could add a member function that does the polymorphic pointer conversion within the class:
class B : private A{
// ...
public:
A* getA() {
return this;
}
};
Which allows you to do this, while still allowing private inheritance:
B* b_ptr = new B("c++");
A* ptr = b_ptr->getA();
// ptr = b_ptr; // only allowed in member functions
I haven't encountered a real world design where this trick would be useful, but suit yourself.
PS. Remember that you should destroy objects that you create. Also do realize that delete ptr
has undefined behaviour, unless ~A
is virtual.
Even though I find it quite strange to hide the base class and want to cast B
to A
, you can use for that the operator A*()
.
It follows a minimal, working example:
#include <iostream>
#include <string>
class A{
int a;
public:
virtual void sayHello(){ std::cout << "Hello\n"; }
};
class B : private A{
std::string name;
public:
B(std::string _n): name(_n){}
operator A*() { return this; }
void sayName(){std::cout << name << "says hello\n";}
void sayHello(){sayName();}
};
Now you can use it as:
int main() {
A *ptr = *(new B("c++"));
ptr->sayHello();
return 0;
}
Or even better:
int main() {
B b{"c++"};
A *ptr = b;
ptr->sayHello();
return 0;
}
Adding the cast to A&
is as easy as adding the member method operator A&()
defined as return *this;
.
There is an unsightly way around this: C style casts. C style casts can cast to inaccessible base classes. This is the one and only case where C style casts can do something that C++ casts can't. From cppreference, when a C style cast (T) foo
attempts to perform static_cast<T>(foo)
, it can do slightly more than just a static_cast
:
[P]ointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier).
Emphasis added
Thus, you can do this:
int main() {
A *ptr = (A *) new B("c++");
ptr->sayHello();
return 0;
}
This is ugly, and it comes with all the disadvantages of casting and especially of C style casts. But it does work, and it is allowed.
Live on Wandbox
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With