-1

I was reviewing inheritance and I saw the three rules of casting based on the following code. (from https://www.youtube.com/watch?v=EYuPBkgJtCQ)

class B{};
class D_priv: private B{};
class D_prot: protected B{};
class D_pub: public B{};

Three rules:

  1. Anyone can cast a D_pub* to B*. D_pub is a special kind of B.
  2. D_priv's members and friends can cast a D_priv* to B*.
  3. D_prot's members, friends, and children can cast a D_prot* to B*.

I am so confused about how to understand these three rules. Is there a general condition for casting? Does members, friends and children mean here?

My question is mainly about the casting instead of the inheritance.

Lusha Li
  • 319
  • 3
  • 11
  • @UKMonkey, the post you referred is talking about the inheritance but I am asking about the casting. – Lusha Li Aug 13 '18 at 08:56
  • Read your rules; read the answer to the question; you'll find that they're the same. – UKMonkey Aug 13 '18 at 08:57
  • @UKMonkey, I don't know what's the general condition for casting. – Lusha Li Aug 13 '18 at 09:01
  • you can cast if you know how to. A private base is basically not visible to others, thus would not know the relation between `D_priv` and `B`. And you cannot cast between unrelated types. – apple apple Aug 13 '18 at 09:01
  • @apple apple, this is what I want to ask. Thanks a lot~ But based on rule 2, D_priv's members and friends can cast a D_priv* to B*. Is this contradict with what you said? – Lusha Li Aug 13 '18 at 09:06
  • There's not really a special rule for conversion, explicit (i.e., casting) or not. You can find out where the conversion is valid by answering the question "who knows that this class inherits from `B`?" – molbdnilo Aug 13 '18 at 09:06
  • @molbdnilo, the trick you told is very useful. I have one more question. In the rule, why it says "D_priv's members and friends" can cast a D_priv* to B*? Isn't the casting between two classes? Can I understand it as "pointers in D_priv and its friend class can be cast to pointers in B class"? – Lusha Li Aug 13 '18 at 09:20
  • @LushaLi A private base is basically not visible to **others**. Which does not contains member and friends. – apple apple Aug 13 '18 at 09:27
  • @LushaLi The interesting conversion is between pointers - in 99.999% of cases it is a mistake to convert (which would copy) an object into an instance of a base class (this is called "slicing"). I think you would benefit from one of [the recommended books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – molbdnilo Aug 13 '18 at 09:27

1 Answers1

1

In order to be able to cast from a class to a parent class, the public members of the parent class must be available. More exactly, the public members of the parent must be callable when calling them on the child class to whoever is casting it.

You can ask yourself this question: if I create an object of type B, can I call a public method of D_prot? If the answer is yes, then you can cast it, e.g.:

class A
{
public:
    void foo();
};
class B : public A 
{
};
// Then when someone has a B object:
B b;
b.foo(); // Are we allowed to call foo()?
static_cast<A>(b).foo(); // If yes, we can cast it as well

A more exhaustive version looks like this:

class Base
{
public:
    void foo() {} // Dummy method to clarify the example
};

class PublicChild : public Base
{
public:
    void test()
    {
        foo(); // OK, we have access to Base public members
        static_cast<Base*>(this)->foo(); // OK
    }
    friend class PublicFriend;
};

class PublicFriend
{
    void test(PublicChild* p)
    {
        p->foo(); // OK, the method is public anyway
        static_cast<Base*>(p)->foo(); // OK
    }
};

class ProtectedChild : protected Base
{
public:
    void test()
    {
        foo(); // OK, we have access to Base public members
        static_cast<Base*>(this)->foo(); // OK
    }
    friend class ProtectedFriend;
};

class ProtectedFriend
{
    void test(ProtectedChild* p)
    {
        p->foo(); // OK, because we are a friend of ProtectedChild, we have the same visibility as ProtectedChild itself
        static_cast<Base*>(p)->foo(); // OK
    }
};

class PrivateChild : private Base
{
public:
    void test()
    {
        foo(); // OK, we have access to Base public members
        static_cast<Base*>(this)->foo(); // OK
    }
    friend class PrivateFriend;
};

class PrivateFriend
{
    void test(PrivateChild* p)
    {
        p->foo(); // OK, because we are a friend of PrivateChild, we have the same visibility as PrivateChild itself
        static_cast<Base*>(p)->foo(); // OK
    }
};

int main()
{
    Base b;
    b.foo(); // OK: public method

    PublicChild p1;
    p1.foo(); // OK: public inheritance makes Base::foo public
    static_cast<Base>(p1).foo(); // OK

    ProtectedChild p2;
    p2.foo(); // error: protected inheritance makes Base::foo protected
    static_cast<Base>(p2).foo(); // error

    PrivateChild p3;
    p3.foo(); // error: private inheritance makes Base::foo private
    static_cast<Base>(p3).foo(); // error
}

Example: https://ideone.com/Zbaqbu

PS.in the link I have commented the lines which do not compile, feel free to fork the code and uncomment them to see what the compiler tells

vdavid
  • 2,434
  • 1
  • 14
  • 15