Ссылка указателя и оператора левого сдвига

Я переопределил оператор << и хочу получить ссылку на указатель.

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...
Другие вопросы по тегам