A trick to enable casting over non-public inheritances - c++

This is a followup related to my previous question where I investigated the problem and found that up- and downcasting seem to be working correctly over public inheritance relations. For example, this code does not even compile:
class A {
};
class B : protected A {
};
int main() {
B b;
static_cast<A*>(&b);
};
G++ gives the following error:
t.cc: In function ‘int main()’:
t.cc:10:21: error: ‘A’ is an inaccessible base of ‘B’
10 | static_cast<A*>(&b);
| ^
However, I think I found the following trick to overcome this limitation. We can cast inside the class, and then export the casting functionality as a public method:
#include <iostream>
class A {
};
class B : protected A {
public:
A* getA() {
return static_cast<A*>(this);
};
static B* fromA(A* a) {
return static_cast<B*>(a);
};
};
int main() {
B b;
// Does not even compile
//std::cout << static_cast<A*>(&b);
// works like charm
std::cout << b.getA() << '\n';
// works also in the reverse direction, although it needs a static method
std::cout << B::fromA(b.getA()) << '\n';
};
I admit it is not very pretty. My tests (in more complex code) show it working, but I am still unsure.
Is it valid C++ code and correct practice?

Conceptually getA is fine. B is choosing to expose the A in it. It can be simplified to return this;, the cast is unnecessary.
I have reservations about fromA, because it is implying that all As are Bs, which might not be true. You should limit the accessibility of fromA to places where you can prove all the As are Bs.
Safe downcast may be done with dynamic_cast.
cppreference on static_cast

Related

Virtual functions only called when using an indirection — Classical early binding issue?

I have three different implementations of an interface (solving systems of equations). The old interface essentially was void foo(int *f) within a class. Now I want to generalize this to a case where I solve N systems at the same time. For this I want to have the interface void foo(int *f[N]).
In the codebase there is an abstract class defining the interface, then three classes derive from that class. I would like to add my generalization without breaking existing code. Therefore I thought of adding the new interface and have the old interface delegate to the new one. This is my compressed version:
#include <iostream>
struct AbstractClass {
/// Old interface, needs to be retained.
virtual void foo(int *f) {
std::cout << "AbstractClass::foo(int *f)\n";
int *a[2] = {f, nullptr};
foo(a);
}
/// New interface.
virtual void foo(int *f[2]) {
std::cout << "AbstractClass::foo(int *f[2])\n";
}
};
struct Derived : public AbstractClass {
/// New interface.
void foo(int *f[2]) override {
std::cout << "Derived::foo(int *f[2])\n";
}
};
int main(int argc, char **argv) {
// Code using the old interface.
Derived d;
int *a;
d.foo(a);
}
Work with the code.
My hope is that the call of d.foo(a) would go to the inherited Derived::foo(int *f) and from there to Derived::foo(int *f[2]). However, g++ 6.3 gives me the following (in C++11 mode):
inheritance-test.cpp: In function 'int main(int, char**)':
inheritance-test.cpp:31:12: error: no matching function for call to 'Derived::foo(int*&)'
d.foo(a);
^
inheritance-test.cpp:21:10: note: candidate: virtual void Derived::foo(int**)
void foo(int *f[2]) override {
^~~
inheritance-test.cpp:21:10: note: no known conversion for argument 1 from 'int*' to 'int**'
It looks like the derived objects do not really have inherited the methods that I want.
Using runtime polymorphism with a pointer to the base class does work, though:
AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);
delete pd;
I do not really understand why it does not work without the pointer. The vtable is not used with automatic storage because the function calls are bound at compile time (early binding)?
This is getting me a bit closer to the solution, but I would still have to touch all the code which uses this library. However, that is not really an option, the old stuff has to keep working.
What can I do about that (other than duplicating all code)? Would it be sufficient to have this delegation copied into each derived class?
There is something known as name hiding in C++. Basically, when you override a member function in a derived class, it hides all other overloads found in the base class.
That is why below fails:
Derived d;
int *a;
d.foo(a);
And below works:
AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);
Because the overload of foo that takes a pointer is in AbstractClass but is hidden in Derived.
You can make those overloads visible with a using.
struct Derived : public AbstractClass {
using AbstractClass::foo;
void foo(int *f[2]) override {
std::cout << "Derived::foo(int *f[2])\n";
}
};
Demo

error: 'A' is an inaccessible base of 'B'

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
When you want to hide that A is a base of B this is valid.
But you assignment
A *ptr = new B("c++");
breaks this hiding, because you use an A*. So c++ generates an error because the dependency is hidden. You can do
B *ptr = new B("c++");
though.

C++ Call a function in a derived class from base class without casting and no virtual methods

I was recently asked this question in an interview:
#include <iostream>
class Base
{
public:
void foo() { std::cout << "foo" << std::endl; }
};
class Derived : public Base
{
public:
void bar() { std::cout << "bar" << std::endl; }
};
int main(int argc, const char *argv[])
{
Base *p = new Derived;
// additional code here
return 0;
}
The conditions on the question were that the Base and Derived classes cannot be changed (for example changing the name of the methods, adding additional methods, or changing a method to virtual.
A further restriction was that no type of cast could be used.
The pointer p had to be used.
Other than that, you could write any additional code, including as many classes as necessary to insure that the "bar()" method was called using the object pointed to by p.
Given that no casts were allowed, the only aswer I could come up with was an old-school one:
Derived *d;
memcpy(&d, &p, sizeof p);
d->bar();
Which is even worse than a cast.
The interviewer berated me and told me I didn't have even the most basic knowledge of object hierarchy since I could not see the very obvious, trivial solution to the question.
I apologize if this question is a duplicate; I've seen other questions about accessing a method in a derived class from a base class, but in all cases I saw, the answer involved either a cast or modification to either of the classes.
He may be correct; I've been programming in C++ for over 15 years and I cannot see the solution. It could be I've never encountered it since I would use a cast in this situation: in this case, it would have to be a static_cast since there are no virtual methods (not even the destructor) which would allow the dynamic_vast to compile (it fails with a message: "'Base' is not a polymorphic type"
Simple and easy dumb:
#define Base Derived
just before main. (you can then call bar on it)
I maybe would come up with something like:
void foobar(Base* b){
Derived d;
d.bar();
}
int main(int argc, const char *argv[]){
Base *p = new Derived;
foobar(p);
return 0;
}
And if the interviewer complains that this is too foobar, I would ask him to please ask less foobar questions :P
No, really, I do consider this as a valid answer to a quite academic question. I am using the object pointed by p (to call a foobar function) and I made sure that 'bar()' is called. I dont think such an exercise deserves a more sophisticated solution. Logically, my solution cannot be distinguished from whatever solution the interviewer had in mind.
The pointer p had to be used. Other than that, you could write any additional code, including as many classes as necessary to insure that the "bar()" method was called using the object pointed to by p.
As many classes as necessary, you say?
#include <iostream>
class Base
{
public:
void foo() { std::cout << "foo" << std::endl; }
};
class Derived : public Base
{
public:
void bar() { std::cout << "bar" << std::endl; }
};
int main()
{
class Base
{
public:
void bar() { std::cout << "bar" << std::endl; }
};
class Derived : public Base
{
};
Base *p = new Derived;
p->bar();
}
You could use a union for type-punning:
union {
Base* bp;
Derived* dp;
} my_union = {p};
my_union.dp->bar();
Answer could be: This will not compile.

Partially hidden inheritance tree

I have a class tree as such:
class A;
class B : public A;
I then want to create a class which is derived from class B. But I want that derivation to be hidden from outside members as well as anyone else that inherits from class C
class C : private B;
void test() {
C c;
B *b = &c; // compiler error: B in C is private and is therefore not type compatible. This is desired.
}
However, I also want to reveal the inheritance of class A. Hiding class B in this case also hides class A.
void test2() {
C c;
A *a = &c; // Compiler error: A is only accessible through B which is not possible with a private inheritance of B. This is not desired; this conversion should be possible.
}
I could inherit from A again, but that would obviously create duplicate member variables if A has any. I could create a virtual inheritance of class A, however I don't feel it would have the exact effect I desire since that would affect the entire tree rather than this segment (right?)
I suppose the obvious solution would be to create a typecasting member function:
class C : private B {
A * turn_into_A() {
// Since B is an A and we are still in the scope of C, this will succeed
return this;
}
};
However, I'd prefer to avoid explicit typecasts such as that case,
Any sane person might tell me I'm doing this wrong. They'd probably be right. But I would like to know simply for knowledge's sake: is there a way to do this without virtual inheritance or an explicit member function's typecast?
I found a workable solution:
class A {
public:
void somethingA() {
std::cout << "a" << std::endl;
return;
}
};
class B :
public A {
public:
void somethingB() {
std::cout << "b" << std::endl;
return;
}
};
class C :
private B {
public:
using B::A; // While B is private (and hidden), this exposes access to B::A
void somethingC() {
std::cout << "c" << std::endl;
return;
}
};
int main(int argc, char **argv) {
C c;
B* b = &c; // Compiler error: cannot convert because B is private (desired)
A* a = &c; // Okay! (required)
c.somethingC();
c.somethingB(); // Compiler error: private. (desired)
c.somethingA(); // Compiler error: A is exposed, but not A's members. This can be solved by adding 'using B::A::somethingA()' in class declaration (undesired but acceptable in my situation)
a->somethingA(); // Okay! (of course)
}
It's not perfect in that it only exposes C to be able to be converted to A (which for my purposes is what I'll end up doing anyway, so that's fine). However it doesn't directly expose the members of A to allow C to be used as-an-A, eg you cannot call c::somethingA() unless you specifically also expose B::A::somethingA.
Inheritance depicts a IS-A relationship. So, in your object model, B IS-A A, C IS-A B. So, why don't you use
class C : public B { ...};
So that you may view a C object as a B object as well as an A object as need be. Hope that helps.

checking a private variable using a derived class object

below is the small program.
i want to check the value of the private variable x of class A using the object of class B.
is it possible ever?
#include<stdio.h>
#include<conio.h>
#include<iostream>
class A {
int x;
public:
A() {
x=10;
}
};
class B : public A {
public:
int x;
};
int main()
{
B obj;
obj.x=20;
std::cout<< obj.x;
getch();
}
This will output 20, but how can i check the value of x as 10 which is in class A?
i wanted to know whether we can check the value without making x as protected!
You'll have to make the variable protected, or, you can create a protected member method in class A which returns the variable x.
By using the 2nd approach (protected member method or property (is that possible in C++?), class B can read the variable, but cannot change it.
Derived classes cannot see ancestor privates. You can use "protected" for descendents to see the data, but not unrelated classes.
In addition to the private / protected issue, your B::x member over-shades the x of A. So even if both were public, you'd have to write b.A::x. Looks weird, but works (see code below) ....
This is syntax-wise. You should tot do this, of course, as everybody here say. use protected members with meaningful names, and accessor functions
class A {
public:
int x;
};
class B: public A {
public:
int x;
void f() { std::cout << "B::x=" << x << ", A::x=" << A::x << '\n'; }
};
int main()
{
B b;
b.A::x = 10;
b.x = 20;
b.f();
}
output:
B::x=20, A::x=10
You can not examine the value of private members of base class. So: add an accessor in A or make A::x protected.
Make x in A protected and write a method in B that looks something like this:
int getAX(){
return A::x
}
You shouldn't.
Since your A class tells the member is private, nobody but A can access it.
If B is-an-A, the same rule is valid: A::x is still inaccessible.
Your wanting to access it means you either need a different kind of A (i.e. make A::x public), or you want the wrong thing.
Well, if you really want to know if it's possible: it is. public, protected and private are only compile time checks. One possible option to circumvent them during runtime is the following:
#include <iostream>
class A{
int x;
A() : x(10){}
};
struct pubA{
int x;
};
int main(){
A a;
// evil casting
pubA* pa = reinterpret_cast<A*>(&a);
std::cout << pa->x << std::endl; // should print 10
}
That said, don't do it. There is a reason for these keywords. (The above code is untested, 'caus I'm writing from my iPod. If reinterpret_cast doesn't work, use old C-style cast: pa = (pubA*)&a.)