how to implement casting to a private base class i

2019-08-11 09:23发布

问题:

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

回答1:

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.



回答2:

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.



回答3:

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