Ссылка указателя и оператора левого сдвига
Я переопределил оператор << и хочу получить ссылку на указатель.
class foo
{
foo();
virtual ~foo();
void operator << (BaseService*& iRight);
}
Где-то в коде, с экземпляром foo и сервисом, который является специализацией класса BaseService, который я делаю:
Service* service_pointer = new Service();
foo_instance << service_pointer;
Но я получаю эту ошибку: ошибка: нет совпадения для 'operator<<' в примечании 'foo_instance << service_pointer': кандидаты: void foo:: operator << (BaseService * &)
Ничего не изменится, если я dynamic_cast мой service_pointer для BaseService
Service* service_pointer = new Service();
foo_instance << dynamic_cast<BaseService*>(service_pointer);
Любая идея?
4 ответа
Первая версия не работает, потому что вы не можете передать ссылку на указатель на подтип, и это правильно: что если реализация operator<<
сделал указатель, указывающий на экземпляр MyService
(который является подклассом BaseService
, но не из Service
)? Очевидно, это было бы незаконно для Service*
указать на MyService
, Так проходя в Service*
не допускается.
Вторая версия не допускается, потому что dynamic_cast
не возвращает l-значение, поэтому вы не можете передать его как неконстантную ссылку.
Единственное, что вы можете сделать, это определить другую переменную типа BaseService*
и передать это в качестве аргумента <<
, Если <<
затем переназначает указатель, это изменение будет видно только для вновь созданной переменной и не повлияет ServicePointer
,
При этом (и не зная вашего варианта использования) я должен сообщить вам, что имея operator<<
возьмите неконстантную ссылку на что-либо, поскольку его правильный операнд кажется мне плохой практикой. Вы обычно не ожидаете <<
изменить его правильный операнд.
Просто так Service *
тип конвертируется в BaseService *
тип никоим образом не означает, что Service *&
тип конвертируется в BaseService *&
тип. Это не так. Вот почему ваш первый вызов не компилируется.
Пытаясь использовать dynamic_cast
(или любой другой не взломанный актерский состав) не поможет. Результат такого броска не является lvalue. И вы не можете привязать неконстантную ссылку к чему-то, что не является lvalue. Вот почему ваш второй вызов не компилируется.
Если вы действительно хотите, чтобы ваш оператор принял BaseService *&
, тогда вы ограничены выполнением ручного предварительного преобразования Service *
к значению типа BaseService *
(т.е. к явному объекту указателя) и затем вызов оператора с этим lvalue
Service* service_pointer = new Service();
BaseService* base_service_pointer = service_pointer;
foo_instance << base_service_pointer;
Ваши звонки оператору <<
будет компилироваться, если вы измените объявление, если оператор
void operator <<(BaseService* const& iRight);
но можете ли вы сделать это или нет, зависит от ваших намерений. Почему вы пытаетесь передать указатель по ссылке?
Вы должны на самом деле определить BaseService
переменная указателя.
Service* service_pointer = new Service();
BaseService* base_service_pointer = dynamic_cast<BaseService*>(service_pointer);
foo_instance << base_service_pointer;
Поскольку вы хотите взять ссылку на указатель, она не может быть значением.
Также обратите внимание, что dynamic_cast<>
это не обязательно здесь. static_cast<>
был бы в фокусе. Еще лучше, используйте простое задание из service_pointer
в base_service_pointer
!
Это не может работать, потому что ссылка не является константой, поэтому вы можете изменить значение указателя в foo::operator<<. Рассмотрим следующий пример:
class Service1 : BaseService
{
};
class Service2 : BaseService
{
};
void foo::operator << (BaseService*& iRight)
{
// ok, iRight is a reference to BaseService*
// so we can assign Service2* to it, can't we?
iRight = new Service2();
}
Service1* service_pointer = new Service1();
foo_instance << service_pointer; // oops...