c ++ dynamic_cast - PullRequest
       18

c ++ dynamic_cast

2 голосов
/ 16 марта 2011
class CBase { };
class CDerived: public CBase { };

CBase     b; 
CBase*    pb;
CDerived  d; 
CDerived* pd;

pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived

Я знаю, что «основание к производному» приведено неверно.Но какова внутренняя причина этого?Какая логическая причина внутри?Это трудно запомнить без объяснения причин.спасибо!

Ответы [ 4 ]

6 голосов
/ 16 марта 2011

Во-первых, CBase должен быть полиморфным, чтобы вы могли использовать dynamic_cast здесь (то есть он должен иметь хотя бы одну virtual функцию-член). В противном случае вы не можете использовать dynamic_cast.

Тем не менее приведение от &b к CDerived* равно , а не неправильно: pd будет нулевым указателем.

dynamic_cast обладает полезным свойством, что при сбое приведения (то есть, если объект, на который указывает указатель, не относится к целевому типу), он возвращает нулевой указатель. Это позволяет вам проверить фактический тип объекта. Например:

CBase b;
CDerived d;

CBase* pb = &b;
CBase* pd = &d;

CDerived* xb = dynamic_cast<CDerived*>(pb); // xb is null!
CDerived* xd = dynamic_cast<CDerived*>(pd); // xd points to d!

Ваш код был бы неверным, если бы вы использовали static_cast, поскольку он преобразуется без выполнения какой-либо проверки типа во время выполнения, что означает, что нет способа проверить, успешно ли приведено приведение. Если вам когда-либо нужно привести иерархию классов, и вы точно не знаете, принадлежит ли объект к производному типу, к которому вы пытаетесь привести тип, вы должны использовать dynamic_cast.

2 голосов
/ 16 марта 2011

Для преобразования из производного в базовое вам не нужно (и обычно не нужно ) вообще явно указывать приведение:

CDerived d;
CBase *pb = &d;   // perfectly fine

Основа для производного приведения не совсем неверна, хотя вы обычно предпочитаете ее избегать. Причина этого довольно проста: указатель на базу может указывать на фактический базовый объект или что-либо производное от него. Если вы собираетесь понижать рейтинг таким образом, вам, как правило, нужно проверить, успешно ли выполнено преобразование. В указанном вами конкретном случае это не удастся, поэтому то, что будет назначено (результат dynamic_cast), будет просто нулевым указателем.

В большинстве случаев вы предпочитаете указывать полный интерфейс к объектам класса в базовом классе, поэтому вам редко нужны большие откаты.

1 голос
/ 16 марта 2011

Производный класс может иметь больше «поведений», чем базовый класс.Больше функций-членов, больше данных-членов и т. Д. Если вы приведете базовый класс к производному классу, а затем попытаетесь трактовать его как производный класс, вы попытаетесь заставить его делать то, чего он не может делать.Поскольку вы пытаетесь заставить экземпляр класса base делать то, что знает только класс производный .

0 голосов
/ 16 марта 2011

pd - указатель типа CDerived*. Таким образом, pd указывающий объект должен иметь в своем составе два подобъекта (т.е. базовый и производный). Но с этим утверждением -

pd = dynamic_cast<CDerived*>(&b);

Здесь pd указывает только на базовый подобъект. Нет частичного способа указания на подобъекты. Так что это неправильно.

...