2015-11-10 3 views
1

Я пришел из Java, поэтому при необходимости вызывать функцию так:Понимание литья в C++

struct A { 
    int a; 
    A(int a) : a(a){ } 
}; 

A foo(A a){ 
    return A(a); 
} 

Я стараюсь писать что-то вроде

A a = foo(A(10)); 

и это работает прекрасно. Но я узнал, что это также можно сделать таким образом:

A a = foo(static_cast<A>(10)); 

I.e. он обеспечивает неявное преобразование. Итак, как правило, мы должны использовать стиль static_cast, когда нам нужно использовать неявное преобразование? Или есть случаи, когда могут быть нужны функции/C-стиль?

+4

Вы также можете написать 'A a = foo (10);' – emlai

+0

Возможный дубликат [Когда должен использоваться статический \ _cast, dynamic \ _cast, const \ _cast и reinterpret \ _cast?] (Http: // stackoverflow. com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used) –

+1

@zenith Конечно, в этом случае я могу. Но часто бывает, что конструктор «явный». – stella

ответ

2

Есть два отдельных аспект стоит (перо) рассмотрения здесь: следует A::A(int) оставить неявные, и как лучше построить A к перейдите к foo.

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

Для строительства используйте A(10) (также работает C++ 11, A{10}) или просто 10, чтобы полагаться на неявное преобразование. Обратите внимание, что A(10) - это вызов конструктора, а не бросок: нет необходимости рассматривать static_cast<>() в качестве предпочтительной нотации. Старая литовая нотация C-стиля на самом деле (T) cast-expression, на 5.4 [expr.cast] в стандарте C++.

3

Вам не нужны стили C-стиля на C++. Что касается ваших примеров, наиболее распространенный способ, чтобы написать это было бы это:

A a = foo(A(10)); 
2

Если вы хотите, чтобы сделать переход от типа A к B, у вас есть два синтаксиса, чтобы определить преобразование:

class B 
{ 
public: 
    B(A); # Conversion constructor. 
}; 

или

class A 
{ 
public: 
    operator B(); # Conversion operator. 
}; 

Для случая, как:

void f(B b); 

int main() 
{ 
    A a; 
    f(a); 
} 

Если существует первая версия, она создает временный объект класса s B, используя a как параметр. Если вторая версия существует (и вы ее реализуете, конечно), она вызывает operator B() класса A для создания объекта типа B от a. Если они существуют, компилятор выдает сообщение об ошибке двусмысленности.

О путях/повышающих каскадах, неявные преобразования позволяют повышать уровень (если исходные и целевые типы являются ссылками/указателями), даже если целевая база является неотъемлемым (частным) базовым классом источника. Неявные преобразования также позволяют преобразовать из неконстантного исходного типа в целевой тип const, а также преобразовать из rvalue в lvalue и так далее.

Это, короче говоря, правила неявных преобразований. Более полное руководство (с учетом встроенных и пользовательских типов и встроенных преобразований) - here.

Если вы используете C++ - литье:

f(static_cast<B>(a)); 

его почти то же самое, но с некоторыми отличиями: если B является innaccesible (частная) база a, бросок не допускается. Другая разница заключается в том, что downcasting разрешен без проверки времени выполнения (если B является производным классом A, он позволяет выполнять кастинг, даже если a на самом деле не является объектом типа B). Это допустимо, потому что проверка времени выполнения медленная, поэтому, если вы знаете, что a действительно имеет тип B, вы можете безопасно применять кастинг без проверки времени выполнения.

Других отливок:

const_cast<B>(a) 

Только для перехода от сопзИ к неконстантным и наоборот.

reinterpret_cast<B>(a); 

Бросьте все. Почти никаких правил. Если конверсия из a в B не существует, она просто занимает область памяти a и возвращает ее как объект типа B. Его самый быстрый бросок живой.

dynamic_cast<B>(a); 

Даунсайдинг с проверкой времени выполнения (оба типа должны быть ссылками или указателями). Если реальный тип a не является B (даже базовый класс реального типа a), исключение или нулевой указатель выбрасывается/возвращается (в соответствии с тем, если или B являются ссылками или указателями).

Наконец, C-литье:

f((B)a); 

Что C-литейный это попробовать различные отливки (кроме dynamic_cast, а также позволяет приведение к innacesible базовых классов) и использовать первый, который работает. Я бы сказал, что C-casting так же мощен, как и неявный литье.

Явный отливка с синтаксисом несильно вызова:

f(B(a)); 

эквивалентно C-кастинг в поведении.