5

How to implement casting to a private base class in C++? I don't want to use hacks such as adding a friend etc. Defining public casting operator does not work.

EDIT :

For example I have:

class A {
//base class
}

class AX : private A {
//a child
}

class AY : private A {
//another specialized child
}

class B {
//base class
void do (A a) {//do
    }
}

class BX : private B {
//a child
void do (AX a) {
     B::do( static_cast <A> (a) );
    }
}

class BY : private B {
//another specialized child
void do (AY a) {
    B::do( static_cast <A> (a) );
    }
}

EDIT2

Why do I do this?

Suppose I have to define some property which is quite heavyweight and can be of several similar types (like VelocityX VelocityY etc). Then I want to be able to have classes which can have any set of these properties. If I want to process these properties, it is obvious, that I'd rather cast them to their base type than to add an implementation for each variation. I do not use public inheritance because it's better to explicitly cast where needed than to have the private interface implicitly visible. Not a real problem but I'd like to have a solution :)

  • 3
    Could you please tell us what you want to do? This looks like very poor design. Why don't you use public inheritance? Or composition, and a getter function? Could you also provide us with the code which doesn't work? – Alexandre C. Sep 17 '10 at 19:59
  • 5
    Note that many do not consider `friend` a "hack". – Martin Ba Sep 17 '10 at 20:01
  • When you have a lot of classes that might need being added to that friend list I consider it a hack –  Sep 17 '10 at 20:06
  • 1
    Some nice slicing you have up there... – gpeche Sep 17 '10 at 20:26
  • `private` inheritance *means* "Don't treat this as its base." This has a very strong code smell. I'd suggest rethinking your approach entirely. – greyfade Sep 18 '10 at 00:56
  • Another reason to want to do something like this is to be able to force the base class interface access to CONST for external users. In other words, inherit privately, then add a const& conversion operator that returns *this. Unfortunately, the standard doesn't seem to consider this situation as valid, because it doesn't work. – Robert Mar 26 '23 at 00:32

3 Answers3

7

If defining a public casting operator does not work, you can try with a regular function:

class D: private B {
    public:
        B& asB() { return static_cast<B&>(*this); }
};
...
D d;
d.asB().methodInB();
...

Anyway, what is the point? If D derives privately from B, then you are not supposed to use a D as a B from the outside.

gpeche
  • 21,974
  • 5
  • 38
  • 51
3

You can just use a C-style cast. No need for any "hacks" or "implementations". Wrapping it into an explicit function serves the "C-Style casts are bad" people

template<typename Targ, typename Src>
typename boost::enable_if<boost::is_base_of<Targ, Src>, Targ>::type &
private_cast(Src &src) { return (Targ&)src; }

To have the cast safe, you need to ensure that Targ is actually a private or public base. This is done by boost::is_base_of.


Of course you should prefer member functions in the respective derived class that return the base pointer, instead of doing such a cast..


Defining public casting operator does not work.

That doesn't make sense to me... Why make the base class private at all then? Just make it public. The reason your conversion functions don't work is because the Standard requires that implicit conversions never consider conversion functions to a base class, the class itself or void.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    The result of your C-style cast (equivalent to reinterpret_cast in this case) is implementation-defined, isn't it? – avakar Sep 17 '10 at 20:37
  • 4
    @avakar it is not equivalent to a reinterpret_cast, but to a static_cast with access checking disabled (see `5.4/7`). – Johannes Schaub - litb Sep 17 '10 at 20:51
  • My deity, it's true! +1 from me. – avakar Sep 17 '10 at 21:09
  • "Wrapping it into an explicit function serves the "C-Style casts are bad" people" : Is there something wrong with people believing C-style casts in C++ are wrong? I mean: I've had bugs hidden by C-style casts that would have been caught by a static_cast (cast from Derived * to Base2 *, those types being only forward declared). Did I miss something? – paercebal Aug 06 '14 at 14:56
  • @paercebal they are as wrong and as right as people who say that blue is a nice color. Write what you think is most readable and maintainable for you and your co-workers. In the case of casting to a private base class, I would have wrapped it into a function aswell, for the record. But I won't agree with a general and contextless "C-style casts in C++ are wrong". – Johannes Schaub - litb Aug 06 '14 at 17:06
  • @JohannesSchaub-litb : My case is less "blue is nice" and more "fire burns and hurts". The (true life) example: You have a Derived class inheriting non-trivially from a Base class (e.g. anything that would have the address of the "this" pointer of Derived to be different from the address of the "this" of Base). For some reasons, forward-declarations abound, and in one such source, a pointer to Base is cast into a pointer to Derived. The C-style cast silently became a reinterpret cast (corrupting the data), while a C++-style class would have detected the problem at compile time. – paercebal Aug 10 '14 at 18:11
  • @paercebal the statement "fire burns and hurts" suggests that using c style casts burns and hurts significantly more than c++ style casts in each scenario. But I don't think so. IMO that statement is an over-generalization. For a cast that involve class hierarchies, I would use `static_cast` or `dynamic_cast` as appropriate. For many other cases I would use C style casts as appropriate. I don't think that burns and hurts anymore than using only C++ style casts (to the contrary, it would cause more hurt to me to use C++ style casts everywhere!). – Johannes Schaub - litb Aug 11 '14 at 17:53
  • This is only safe in limited cases, like when src has standard layout and Targ is the first base class. In other words, very dangerous to blindly rely on. – Carlo Wood Nov 29 '21 at 17:21
0

I have a use case for this; I am inheriting from a large and volatile base class that is adding functions all the time and almost never is the base class function going to work correctly in my subclass, so I inherit privately.

I think it's simplest just to make a function that returns the base class. Below I list a fully corrected program; please try compiling your code before submitting a question, since using identifiers like "do" as function names is likely to make every compiler unhappy .. :-( :-(

class A {
  //base class                                                                                                                                                          
};

class AX : private A {
  //a child                                                                                                                                                             
 public:
  A *ToA() { return this; }
};

class AY : private A {
  //another specialized child                                                                                                                                           
 public:
  A *ToA() { return this; }
};

class B {
  //base class                                                                                                                                                          
 protected:
  void do_it (A a) {};
};

class BX : private B {
  //a child                                                                                                                                                             
  void do_it (AX a) {
    B::do_it( *a.ToA() );
  }
};

class BY : private B {
  //another specialized child                                                                                                                                           
  void do_it (AX a) {
    B::do_it( *a.ToA() );
  }
};