4

I have seen this example from the book:

class Test: private std::string
{
public:
    Test():std::string("How?")
    {
    }
};

int main(int argc, char** argv)
{
    Test t;

    std::cout<<(std::string&)t<<std::endl;

    return 0;
}

I don't know how did it printed "how" when i typecasted the class name? is it because of operators? but i know that when you do private inheritance, the public and protected variables and methods will be considered "private" outside.

So my question is, how did it exactly printed "How" ?

edit :

so who is holding the string value "How" and how was it printed? Because it was printed by typecasting.

Carlos Miguel Colanta
  • 2,685
  • 3
  • 31
  • 49

2 Answers2

6

This illustrates one of the dangers of the C-style cast : it's the only cast that ignores inheritance access specifiers. As you saw, the cast successfully dug out the std::string base reference, even though it was private. If you try this with a static_cast, it won't compile.

Edit :

The std::string subobject of t is holding "How", as you initialized it in Test's constructor. Casting to a reference to a base class serves to access the corresponding subobject.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Well, i saw this technique from the book "C++ primer" so i kinda wondered. – Carlos Miguel Colanta May 26 '15 at 07:18
  • 1
    @CarloBrew A book that suggests c-style casts is a bit dated, and a book that suggests inheriting from a std container is giving bad advice. – acraig5075 May 26 '15 at 07:20
  • @acraig5075 depends on the context. As long as you always inherit privately if your base class is not virtual-destructible, and you use C-style cast with care and parsimony, everything's fine. – Quentin May 26 '15 at 07:22
  • *"[C-style cast is] the only cast that ignores inheritance access specifiers"* - a `reinterpret_cast` could be used to do this too. – Tony Delroy May 26 '15 at 07:24
  • So the code `(std::string&)t` made it point to the base class? – Carlos Miguel Colanta May 26 '15 at 07:35
  • 1
    @TonyD: No, `reinterpret_cast` would pretend there's a `string` at the same address, giving undefined behaviour if it isn't a standard-layout type. An evil C cast will correctly adjust the address to refer to the base-class subobject, as `static_cast` would if the base class were accessible. – Mike Seymour May 26 '15 at 07:35
  • @TonyD As long as `Test` is a standard-layout type with the `std::string` as first base, yes. But `reinterpret_cast` ignores pretty much everything, so I'm not sure it's worth mentioning it here. – Quentin May 26 '15 at 07:36
  • @CarloBrew yes. The base-class part of `t`, that is. – Quentin May 26 '15 at 07:37
  • 1
    @MikeSeymour: I'm not saying it's better or equivalent or safe, just highlighting that it can also bypass the access specifiers as the text I quoted implied no "new-style" casts were capable of that. Quentin: suit yourself - it's mentioned now in comments anyway for anyone else pedantic enough to read that far.... – Tony Delroy May 26 '15 at 09:54
3

The cast (std::string&)t casts t to a reference to an instance of its base class std::string. C style casts are the only casts that can cast to an inaccessible base class. The effect is the same as with an ordinary implicit conversion to an accessible base class.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • so who is holding the string value "How" and how was it printed? Because it was printed by typecasting. – Carlos Miguel Colanta May 26 '15 at 07:20
  • 1
    The `t` object has a `std::string` sub-object. Every base class introduces a base class sub-object. – Cheers and hth. - Alf May 26 '15 at 07:22
  • which means that, once expression `t` is cast to `std::string&`, it will print `"how"` by your good ole `operator<<(std::ostream&, std::string&)`. – jrok May 26 '15 at 07:24
  • @jrok but when i did the private inheritance, the public and protected functions/variables of base will be converted to private upon inheritance. Doesn't it make the operator inaccessible(including the operators which is on public) ? – Carlos Miguel Colanta May 26 '15 at 07:26
  • You're passing a reference to `std::string` to the iostream << operator. – Cheers and hth. - Alf May 26 '15 at 07:27
  • @CarloBrew That's true when you're working with object/references of `Test`. But expression `(std::string&) t` is not of type `Test`. – jrok May 26 '15 at 07:28