5

I would like to know whether c++ guarantees down-casting grandmother base class to grand child class like curiously recurring template pattern. The following code works well in my environment. However I am not sure it works any conditions/environments. Please tell me what you know. Thank you very much.

PS. Honestly said, I am not sure my way of asking stack overflow is ok or bad. If you find the bad points, please let me know. Thank you again.

#include <iostream>

template <typename GrandChild>
class GrandBase {
public:
    void print(void) {
        const GrandChild* grand_child = static_cast<const GrandChild*>(this);
        std::cout << "GrandChild::value = " << grand_child->grand_child_value << std::endl;
    }
};

template <typename Derived>
class BridgeClass : public GrandBase<Derived> {};

class GrandChild : public BridgeClass<GrandChild> {
public:
    GrandChild() = default;
    virtual ~GrandChild() = default;

    int grand_child_value = 17;
};

void test_down_casting_to_grand_base(void) {
    GrandChild a;
    a.print();
}

int main(int argc, char **argv) {
    test_down_casting_to_grand_base();
    return 0;
}

The output is

GrandChild::value = 17
mora
  • 2,217
  • 4
  • 22
  • 32
  • "The output is" of what? Please provide [a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – Paul Evans Jan 03 '16 at 04:16
  • 1
    @PaulEvans: presumably the output of calling `test_down_casting_to_grand_base`. While the example isn't necessarily 100% complete, it's not missing anything that looks critical to the question. – Cornstalks Jan 03 '16 at 04:18
  • The curiously recurring template pattern is perfectly fine and permitted. I don't know all the different parts of the spec that would define the behavior, but it definitely is a valid pattern that is supported by the standard and has well-defined behavior. – Cornstalks Jan 03 '16 at 04:21
  • Thank you Paul Evans for pointing out the missing part of code. I uploaded it. – mora Jan 03 '16 at 04:23
  • Thank you Comstalks. Please let me explain my question a little bit more. When I learned curiously recurring template pattern(CRTP), example codes have always parent class and child class but I have not seen example code which has grand parent and grand child class. So I would like to confirm CRTP works even across multiple-layer-inheritance. Thank you very much. – mora Jan 03 '16 at 04:28
  • As Nicol Bolas says in his answer, having multiple layers of inheritance is not an issue with CRTP. There isn't anything really special or unique about having multiple layers of inheritance. It's just as well defined as the case with single-layer inheritance. Now, if you start having your classes inherit from multiple parents, interesting things can happen if there is [diamond inheritance](https://isocpp.org/wiki/faq/multiple-inheritance#mi-diamond). But as long as each class only has one parent then you don't have to worry about that at all. – Cornstalks Jan 03 '16 at 04:40

1 Answers1

6

Given the code you've presented, yes, the standard requires that this be permitted. As long as you use the CRTP correctly, the standard requires that it works. Even with other classes in-between.

Do note however that the base class can also access any public members of the middle class. The top-most class overrides it if names conflict, of course.

Also, note that there's a conceptual difference between passing the most derived class and passing the first derived class. The base class can only (directly) access the class you passed in. So if you only pass in the first derived class, if that one itself uses the CRTP with its derived class, your base class won't know about it. Whereas if you pass the most derived class, it can access the most derived one and any public interfaces inbetween.

Which you want to use depends on what effect you intend.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982