24

Can I do this?

class A { ... };

class B : private A
{
    const A &foo() const
    {
        return *((const A *)this);
    }
};

Can I take a subclass that inherits privately from a base class and cast it to a public version of its base class? Can I do this without it having virtual methods?

My guess is yes, but I wanted to make sure it's safe / portable.

M.M
  • 138,810
  • 21
  • 208
  • 365
AdamIerymenko
  • 1,299
  • 2
  • 10
  • 19
  • Without being certain I'd say that's possible, although that would kinda defeat the purpose of private inheritance... – Nbr44 Jul 29 '13 at 13:19
  • I'd say that wouldn't be a good thing to do following the meaning of "private" inheritance. This kind of inheritance means "is implemented in terms of", while public inheritance is an "is-a" relation. – JBL Jul 29 '13 at 13:20
  • Why would you want this horrible hack in the first place? – John Dibling Jul 29 '13 at 13:24
  • "Can" is ambiguous. The compiler will not complain, people will. – n. m. could be an AI Jul 29 '13 at 13:24
  • 1
    Why I would want this horrible hack: The point is to inherit from a key/value dictionary that stores a configuration, to normally hide this dictionary behind friendly-looking methods to get/set various config items, but then to be able to rapidly return the dictionary itself. Returning a copy would be okay, but I wanted to know if I could just return const 'this'. Obviously not necessary, but not pointless from a code-cleanliness and idiomatic code POV. – AdamIerymenko Jul 29 '13 at 13:27
  • @AdamIerymenko: Being able to rapidly return the dictionary itself is contrary to using private inheritence. Something is not right here. Either using private inhetitence, or returning the thing that is privately inherited. Which is it? – John Dibling Jul 29 '13 at 13:34
  • This provides read-only public inheritance. I don't want ordinary code to put arbitrary keys into the dictionary or to do so without going through an accessor. So returning a const reference only provides read-only const public inheritance, something C++ doesn't have. (Does it?!?) – AdamIerymenko Jul 29 '13 at 13:38
  • 3
    It is legal and you don't need the C-style cast. As a matter of fact, the C style cast can be used externally to break the `private` relationship: `B b; A& ar = *(A*)&b;` will gladly compile even outside of the `B` class (i.e. access specifiers are ignored by the C-style cast) – David Rodríguez - dribeas Jul 29 '13 at 13:38
  • 2
    *Why would you want to do this?* -- I have seen something similar used to separate the interface from the implementation. On the interface your type offers X, the implementation is done by registering in a particular API that requires that you extend a type `T`. Inheritance from `T` is not your interface, is a requirement for your particular implementation, and if you change the provider, that inheritance can be dropped without affecting user code. – David Rodríguez - dribeas Jul 29 '13 at 13:40
  • I agree that it's a fairly rare use case. This is the first time in almost 10 years of C++ I've considered doing such a thing. – AdamIerymenko Jul 29 '13 at 13:43

3 Answers3

17

Yes you can: §5.4/7 of the standard:

... the following static_cast and reinterpret_cast operations (optionally followed by a const_cast operation) may be performed using the cast notation of explicit type conversion, even if the base class type is not accessible:

a pointer to an object of derived class type or an lvalue of derived class type may be explicitly converted to a pointer or reference to an unambiguous base class type, respectively;

But try not to as it defeats the purpose of private inheritance.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    Been doing C++ for almost ten years, and I still discover corners of this language. Not sure if that's a good comment about the language or a bad one. Probably a bad one. But hey, why stop now. :) – AdamIerymenko Jul 29 '13 at 13:25
  • 1
    Indeed it has many tricky corners: bare pointers, new vs. new[], dangling references, non-virtual destructors, std::auto_ptr (although thankfully being deprecated) to name a few. I'd even be tempted to add templates to the list but that would risk downvotes / general ridicule! – Bathsheba Jul 29 '13 at 13:28
  • But templates are so much fun! Actually they're my favorite part of the language, though definitely in the Swiss army bazooka category and *not to be over-used*. – AdamIerymenko Jul 29 '13 at 13:30
  • How can you put the words "templates" and "over-used" in the same sentence? Oh wait you didn't. But they're still too close together. – nikolas Jul 29 '13 at 13:33
  • 2
    Recommend editing answer to explicitly state that this is a `static_cast`-like operation and not a `reinterpret_cast` – M.M Mar 31 '16 at 08:44
  • If @nijansen's answer is correct (I suppose it is), then yours is an answer to a different question. – Carsten S Mar 31 '16 at 15:57
  • Hm. but it doesn't seem to work https://godbolt.org/z/8xv3Mfcq6 – Amomum Mar 31 '23 at 17:27
7

Yes, that is explicitly allowed. Alexandrescu uses this extensively in Modern C++ Design for his approach of policy based design:

template <typename Policy>
class foo : Policy
{
    public:
        void do_something()
        {
            Policy & p = *this;
            p.do_something();
        }
};

So while the use cases may be limited, there are some out there.

nikolas
  • 8,707
  • 9
  • 50
  • 70
  • 5
    But this is not a c-style cast is it? It's just an implicit cast to a private base from inside the class. Am I missing something? – unkulunkulu Apr 03 '16 at 09:31
  • Implicit casts are more restricted than c style casts. – nikolas Apr 03 '16 at 09:37
  • 4
    The code sample in your answer doesn't have any C-style casts, nor any code where the base class `Policy` is inaccessible. So it doesn't seem relevant to anything the OP was asking about. – Quuxplusone Jun 12 '17 at 03:21
-5

Base on your question title, the answere depends. But for your case in your source code, the answere is yes.

There are two factor which will impact the answere:

  1. If you using C style cast, it will yes, because cast will call re-interpert cast if no conversion availible. You can cast any type of pointer to the target type of pointer. But if there is MI, the result may be incorrect for most C++ language implementation.

  2. If you do the cast (without C style cast) inside the memeber function, the answere will be yes, because the base class is accessable inside the member function. If the expression is in the location where the base class is inaccessable, you will got compile error.

There are more detail about standard converstion in the C++ standard

A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to cv B”, where B is a base class (Clause 10) of D. 
If B is an inaccessible (Clause 11) or ambiguous (10.2) base class of D, a program that necessitates this conversion is ill-formed. 
The result of the conversion is a pointer to the base class subobject of the derived class object. The null pointer value is converted to the null pointer value of the destination type.

Edit 2: make the answere more detail.

ZijingWu
  • 3,350
  • 3
  • 25
  • 40
  • 4
    The paragraph you quoted is about *implicit* type conversion. It states that if the base class is not accessible, you may not convert a derived class pointer to it. Inside the derived class, the base class is accessible, so this doesn't apply. Additionally, there's a special rule for the C-style cast, see [Bathsheba](http://stackoverflow.com/users/2380830/bathsheba)'s [answer](http://stackoverflow.com/a/17925216/420683). – dyp Jul 29 '13 at 13:39
  • "If you using C style cast, it will yes, because cast will call re-interpert cast if no conversion availible." No, in this case the C-style cast will perform similarly to a `static_cast` via the special rule Bathsheba quoted (i.e. ignoring that the base class is inaccessible). Btw you should use `>` or the quote button to insert quotes, not four spaces or the code button. – dyp Jul 29 '13 at 14:51