Преобразование в базовый класс никогда не использовалось

У меня есть два класса, один из которых является производным от другого (потому что я не хочу раскрывать интерфейс базы). Однако позже я хочу создать ссылку на базу.

Я могу сделать это с помощью обычной функции-члена base(), но не с помощью оператора приведения, потому что этот оператор никогда не вызывается.

clang предупреждает об этом, потому что он говорит, что он никогда не будет вызван.

Почему оператор приведения игнорируется и перезаписывается закрытым элементом? Является ли это несоответствием языка?

На самом деле, я думаю, что он делает общедоступной базовую ссылку и ничего больше. Более того, если бы это сработало, это могло бы быть explicit.

class A{
    int v_;
public:
    void f(){}
};

class B : A{ // A is private base because I don't want the f() interface
    int w_;
public:
    A const& base() const{return *this;}
    /*explicit*/ operator A const&() const{return *this;} // never called, warning in clang
};

int main(){
    A a = {};
    B b = {};
    A const& a2 = b.base();
    A const& a3 = b; // bad, But why?
    A const& a4{b}; // explict doesn't help
    A const& a5 = b.operator A const&(); // works in clang (but with a contradictory warning), doesn't work with gcc
}

person alfC    schedule 06.09.2018    source источник
comment
Явный вызов оператора, как в последней строке, должен работать нормально. Однако стандарт требует, чтобы он не вызывался неявно.   -  person Cheers and hth. - Alf    schedule 06.09.2018
comment
@Cheersandhth.-Альф, хорошая мысль. На самом деле он работает с clang, а не с gcc, и clang не согласуется сам с собой, потому что выдает предупреждение о том, что он никогда не будет использоваться, а затем он используется!   -  person alfC    schedule 06.09.2018


Ответы (1)


В случаях a3 и a4 вы инициализируете ссылку с lvalue. В этой ситуации, если тип, на который указывает ссылка, является базовым классом типа инициализатора, ссылка привязывается непосредственно к инициализатору, никаких преобразований не требуется (C++17 [dcl.init.ref]/5).

Поскольку базовый класс недоступен, программа имеет неправильный формат (dcl.init.ref/4).

Я не уверен в правиле проверки доступа в a5, хотя на практике это кажется спорным, поскольку вы не стали бы разрабатывать код так, чтобы кто-то должен был написать этот синтаксис.

См. также [class.conv.fct]/1:

Функция преобразования никогда не используется для преобразования объекта (возможно, cv-квалифицированного) в (возможно, cv-квалифицированный) тот же тип объекта (или ссылку на него), в (возможно, cv-квалифицированный) базовый класс этого типа (или ссылка на него) или на (возможно, cv-квалифицированный) void.

person M.M    schedule 06.09.2018
comment
Хорошо, я думаю, правило состоит в том, что никогда не бывает автоматического возврата к общедоступному интерфейсу, даже если частный интерфейс недоступен из контекста. Это напоминает мне о функциях-членах, которые не возвращаются автоматически struct A{void f(){}}; struct B : A{private: void f(){};}; B b; b.f() // error. Тем не менее, я думаю, что для этого есть применение (особенно сейчас с ключевым словом explicit). - person alfC; 06.09.2018
comment
Контроль доступа @alfC никогда не используется при разрешении перегрузок и т. д.; вместо этого код разрешается, а затем неправильно формируется, если член был недоступен. - person M.M; 06.09.2018