C ++ ISO Стандартная интерпретация разыменования указателя на базу - PullRequest
1 голос
/ 14 сентября 2011

Мне бы хотелось узнать стандартное представление разыменования указателя на базу, но я не делаю никакого прогресса в его поиске.Возьмем, к примеру, эти два класса:

class Base
{
  public:
    virtual void do_something() = 0;
};

class Derived : public Base
{
  public:
    virtual void do_something();
};

void foo2(Base *b)
{
     Base &b1 = *b; // how this work by standard?
}

void foo()
{
  Derived *d = new Derived();
  foo2(d); // does this work by standard?
}

Итак, в принципе, если разыменовать указатель типа B на объект типа D, произойдет ли нарезка на месте или возникнет временный объект?Я склонен полагать, что временное не вариант, потому что это означало бы, что временное является экземпляром абстрактного класса.

Независимо от правды, я был бы признателен за любые указатели на стандарт ИСО, который говорит один или другой,(Или третий, если на то пошло. :))

РЕДАКТИРОВАТЬ:

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

EDIT2:

В ходе обсуждения стало очевидно, что мой вопрос на самом деле касался разыменованиямеханизм указателя, а не о сращивании или временных.Я благодарю всех за то, что они пытались обдумать это для меня, и я наконец-то получил ответ на вопрос, который меня больше всего озадачил: почему я не могу найти ничего в стандарте по этому поводу ... Очевидно, это был неправильный вопрос, но яполучил правильный ответ.

Thnx

Ответы [ 3 ]

5 голосов
/ 14 сентября 2011
Base &b = *static_cast<Base *>(d); // does this work by standard?

Да.

Но вы можете просто сделать это:

Base &b = *d;

//use b polymorphically!
b.do_something(); //calls Derived::do_something()

Не нужно использовать static_cast.В конце концов, Derived является производным от Base.


Ответ на редактирование:

foo2(d); // does this work by standard?

Да.Указатель типа Base* может быть инициализирован указателем типа Derived*.

-

Base &b = *b; // how this work by standard?

Нет.Они одно имя.Если вы имеете в виду Base &b1 = *b, то да, это работает.b1 относится к объекту, указанному b.

2 голосов
/ 14 сентября 2011

Вырезание объекта происходит только тогда, когда конструктор копирования или оператор присваивания базового класса каким-либо образом участвуют, как при передаче параметра по значению. Вы можете легко избежать этих ошибок, например, наследуя от Boost's noncopyable, даже если только в режиме DEBUG.

Ни указатели, ни ссылки на ссылки, ни разыменование не связаны с созданием или назначением копии. Создание базовой ссылки из производной ссылки совершенно безопасно, это даже стандартное неявное преобразование.

2 голосов
/ 14 сентября 2011

В моем черновике C ++ 11 10 [class.derived] / 1 говорит

[Примечание: оператор разрешения контекста :: (5.1) может использоваться для ссылки на прямой иликосвенный базовый член явно.Это позволяет получить доступ к имени, которое было объявлено в производном классе.Производный класс сам может служить базовым классом, подлежащим контролю доступа;см. 11.2.Указатель на производный класс может быть неявно преобразован в указатель на доступный однозначный базовый класс (4.10). Значение l производного класса может быть связано со ссылкой на доступный однозначный базовый класс (8.5.3).- конец примечания]

В большинстве реализаций ваша функция foo2 будет хранить Base& b как Base*.Это, очевидно, не может быть Base сам по себе, потому что это будет копия, а не ссылка.Поскольку он действует (во время выполнения, а не синтаксически) как указатель, а не как копия, проблем с объединением нет.

В вашем коде до редактирования компилятор узнает, что Base& b на самом деле dэто был бы синтаксический сахар и даже не генерировал бы указатель в сборке.

...