2010-12-10 2 views
0

рассмотреть следующий кодвопрос о получении значения из класса

#include <iostream> 
using namespace std; 
class MyClass{ 
    int a; 
    public: 
    MyClass(int j) {a = j;} 
    int geta(void) {return a;} 
}; 

int main(void) 
{ 
    MyClass ob = 99;    

    cout << ob.geta(); 
} 

выхода этого кода 99 моего вопроса следующего заявления MyClass Оби объявить объект класса MyClass и дают такого рода заявление, что объект равно Некоторое число? Возможно, более конкретная декларация будет MyClass ob (99), что вы думаете?

ответ

2

При создании такого объекта, как

MyClass ob =99 ; 

Вы в основном вызывающего конструктор класса.

То же справедливо, когда объект создается как

MyClass ob(99); 

В этом случае конструктор класса вызывается.

+0

Нет, он не называет конструктор копирования. Добавьте `MyClass (const MyClass & asdf): a (asdf.a) {cout <<" cc call "<< endl;}` в свой код. «cc call» не будет напечатан. – x13n 2010-12-10 08:50:58

+0

@ x13n вы правы, если мне это нравится MyClass obj (99); MyClass ob = obj; то конструктор копирования будет называться – anand 2010-12-10 08:57:51

+0

@ x13n: Вы ошибаетесь и что @ Alien01 был прав в первую очередь. Язык указывает, что `MyClass ob = 99` эквивалентно` MyClass ob (MyClass (99)) `. То есть, компилятор создает временное с неявным конструктором и * затем * копирует его в реальный объект. Эффект, который вы видите (отсутствие вывода от вашего конструктора копирования), обусловлен оптимизацией, когда компилятор может создать временное место в том же месте, что и результирующий объект, и, таким образом, удалить копию. Чтобы проверить это, объявите конструктор копирования закрытым, и вы получите ошибку доступа в коде. – 2010-12-10 09:15:49

3

Вы предоставили конструктор, принимающий int. Без ключевого слова explicit его можно назвать неявным - как здесь. Если вы напишете MyClass ob(99), вы бы назвали этот конструктор явно. Нет разницы, пока вы не объявите конструктор как explicit. Вы получите ошибку компиляции при попытке назначить int объекту с явным конструктором.

EDIT: Я проверил - он действительно использует конструктор копирования, как сказал Дэвид и Alien01. Это просто Visual Studio, который не соответствует стандарту.

2

Это интересная часть:

MyClass(int j) {a = j;} 

По умолчанию, конструктор с одним аргументом неявно, что означает, что компилятор автоматически вызывает его везде, где вы хотите назначить int где MyClass ожидается.

Если вы не хотите этого для вашего класса, просто измените конструктор

explicit MyClass(int j) {a = j;} 

И поведение нет, теперь вам нужно явно (следовательно, ключевое слово) вызов конструктора каждый раз. Обратите внимание, что ключевое слово explicit должно появляться только в объявлении в классе, но не в реализации вне тела.

P.S .: Это, например, как const char* автоматически становится std::string, когда ожидается последний.

1

Общий ответ уже был предоставлен другими лицами, включая @ x13n. Я попытаюсь дать немного более подробное объяснение того, что действительно означает код.

Синтаксис MyObject ob = anotherMyObject; эквивалентен MyObject obj(anotherMyObject);. Значение: копия конструкции ob с объекта anotherMyObject. Компилятор всегда будет соответствовать MyObject ob = ...; с вызовом конструктора копирования (обычно MyObject(MyObject const &), но может также быть MyObject(MyObject&), если пользователь объявляет его как таковой).

В вашем конкретном коде правая сторона не является MyObject, поэтому она не может быть передана в качестве аргумента конструктору копирования, и компилятор попытается преобразовать этот rhs в нечто, что можно использовать с конструктором копирования MyObject, применяя общие правила. В вашем случае, есть неявный конструктор, который принимает int аргумента, и который может быть использован для создания временного MyObject, поэтому компилятор переписывает код, чтобы быть:

MyObject ob(MyObject(99)); 
//    ^^^ temporary created by the compiler to match the copy constructor 

Обратите внимание, что это не то же самое, MyObject ob(99), но комбинация int и конструкторов копирования, даже если общий эффект аналогичен. Если конструктор, принимающий целое число, был объявлен explicit, тогда компилятор не смог использовать его для обеспечения преобразования, и код не смог бы скомпилировать.

В комментарии к другому ответу @ x13n указано, что это не вызов конструктора копирования, как если бы вы добавили трассировку к этому конструктору, трассировка не будет сгенерирована. Это совершенно другая проблема, когда компилятор может оптимизировать копию, создав временный адрес точно таким же адресом, что и ob. Есть два способа проверить это, оба зависят от того, что, хотя компилятор может удалять копию, он должен придерживаться тех же ограничений. Таким образом, мы можем сделать MyObject ob(MyObject(99)) недопустимый двумя способами, либо отключение доступа к конструктору копирования, или отключить вызов конструктора с временным:

class test1 { 
    test1(test1 const &) {} // make the copy constructor private 
public: 
    test1(int) {} 
}; 
class test2 { 
public: 
    test2(test2 &) {} // make the copy constructor take a non-const reference 
         // i.e. disable the use of temporaries 
    test2(int) {} 
}; 
int main() { 
    test1 t1 = 99; // copy constructor is private in this context 
    test2 t2 = 99; // g++: no matching function call to test2::test2(test2) 
        // diagnostics will differ with other compilers 
} 
Смежные вопросы