Подводные камни наследования и вложенных имен - PullRequest
2 голосов
/ 24 марта 2019

Я столкнулся со странным случаем при разработке моего дерева наследования объектов C ++ в проекте. Я ожидал, что нижеприведенное не поможет:

struct A {
    protected:
    struct C { };
};

struct B: A { 
    struct C { };
};

Но, это компилируется просто отлично. Это как переопределение? Я могу видеть, как это не является двусмысленным, потому что они могут быть определены как A::C и B::C, но как это действует в полиморфных случаях? Будет ли он вызывать C предписанного типа или C типа экземпляра? Например, предположим, что приведенный ниже код работает и func существует в обеих реализациях C:

A x = B();
decltype(x)::C::func();

какой C назвал бы их функцию? В более общем смысле, это ресурс, который описывает, как разрешаются подобные фрагменты кода?

1 Ответ

4 голосов
/ 24 марта 2019

Это нормально, потому что у вас есть два не связанных struct C: один B::C, а другой B::A::C. C это просто их сокращенное имя.

Если бы у вас была статическая функция f (), определенная в каждом C, вы могли бы вызывать ее извне структуры и без какого-либо объекта, как вы показали в своем коде:

A a =  B();              // the type of a is A (B is sliced, by the way) 
decltype(a)::C::f();     // so this calls A::C::f() 

Теперь для полноты приведем более развитый пример, который показывает, что ни в коем случае не существует двусмысленности:

struct A {
   struct C { static void f() { cout << "A::C::f" <<endl; } };
};

struct B: A {
    C c1;            // the only C known here is A::C
    struct C { static void f() { cout << "B::C::f" <<endl; }}; // now B::C hides A::C
    C c2;            // so here the closest C known is B::C
    A::C c3;         // and here I can be explicit about the C I want
    using D=A::C;    // and here another way to be explicit:
    D c4; 
};

int main() {    
    B  b; 
    decltype(b.c1)::C::f();    // A
    decltype(b.c2)::C::f();    // B  
}

онлайн-демонстрация

...