Can I cast a derived class to a private base class, using C-style cast?
Asked Answered
S

3

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.

Steno answered 29/7, 2013 at 13:16 Comment(10)
Without being certain I'd say that's possible, although that would kinda defeat the purpose of private inheritance...Hamamatsu
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.Sinus
Why would you want this horrible hack in the first place?Larry
"Can" is ambiguous. The compiler will not complain, people will.Vibrator
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.Steno
@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?Larry
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?!?)Steno
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)Sellers
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.Sellers
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.Steno
A
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.

Agosto answered 29/7, 2013 at 13:21 Comment(7)
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. :)Steno
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!Agosto
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.Steno
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.Relation
Recommend editing answer to explicitly state that this is a static_cast-like operation and not a reinterpret_castString
If @nijansen's answer is correct (I suppose it is), then yours is an answer to a different question.Casual
Hm. but it doesn't seem to work godbolt.org/z/8xv3Mfcq6Hoagy
R
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.

Relation answered 29/7, 2013 at 13:25 Comment(3)
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?Broadspectrum
Implicit casts are more restricted than c style casts.Relation
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.Tilford
I
-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.

Igneous answered 29/7, 2013 at 13:24 Comment(2)
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's answer.Jonson
"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.Jonson

© 2022 - 2024 — McMap. All rights reserved.