"Скобка инициализации". (C++)
Я изучаю C++, C++ Primer plus. Но мне просто захотелось зайти на сайт cplusplus и немного перейти к обработке файлов.
Я довольно хорошо знаю основы обработки файлов из Java, PHP, Visual Basic. Но я наткнулся на довольно странную линию.
ostream os(&fb);
fb представляет файлбуф. Я просто не понимаю синтаксис этого, но я могу понять, что это так же, как:
ostream os = &fb;
Но я никогда не читал об этом способе инициализации переменных.
Вот мне и интересно. Я просто бессмысленный и все время упускаю реальную полезную функцию? Этот способ инициализации просто старый? Это что-то другое?
Заранее спасибо.
5 ответов
Обе формы выполняют инициализацию. Первый синтаксис (с ()
) называется синтаксисом прямой инициализации. Второй синтаксис (с =
) называется синтаксисом инициализации копирования. Они будут действовать одинаково в большинстве реальных случаев, но между ними действительно есть различия.
В ситуациях, когда типы с левой стороны (LHS) и с правой стороны (RHS) идентичны (игнорируя любые константы / изменчивые квалификаторы), оба они действительно одинаковы. Стандарт языка прямо заявляет, что в этом случае =
форма эквивалентна ()
форма.
Но когда типы различаются (а тип LHS является типом класса), эти две формы обычно работают по-разному.
Форма инициализации копирования работает следующим образом: преобразуйте значение RHS во временный объект типа LHS (любым возможным способом: стандартное преобразование, оператор преобразования, конструктор преобразования). А затем используйте конструктор копирования класса LHS, чтобы скопировать временный объект в объект LHS.
Форма прямой инициализации работает следующим образом: просто рассмотрите все конструкторы LHS и выберите наиболее подходящий, используя разрешение перегрузки.
Вы можете сразу заметить, что синтаксис инициализации копирования безоговорочно использует конструктор копирования (копирование и промежуточное временное копирование могут быть оптимизированы, но концептуально они есть). Если класс LHS не имеет доступного конструктора копирования, инициализация копирования безусловно становится некорректной, в то время как прямая инициализация все еще может работать.
Также ключевое слово explicit
Применение к определенному конструктору будет влиять на то, какая форма инициализации доступна для каких комбинаций типов.
Небольшая программа для просмотра, когда вызывается конструктор копирования и когда вызывается перегруженная функция оператора присваивания:
#include <iostream>
using namespace std;
class test
{
public:
// default constructor.
test()
{
cout<<"Default Ctor called"<<endl;
}
// copy constructor.
test(const test& other)
{
cout<<"Copy Ctor called"<<endl;
}
// overloaded assignment operator function.
test& operator=(const test& other)
{
cout<<"Overload operator function called"<<endl;
return *this;
}
};
int main(void)
{
test obj1; // default constructor called.
test obj2 = obj1; // copy constructor called.
test obj3(obj2); // again copy constructor called.
obj1 = obj2; // overloaded assignment operator function.
return 0;
}
Выход:
Default Ctor called
Copy Ctor called
Copy Ctor called
Overload operator function called
Так что в вашем случае конструктор копирования ostream вызывается в обоих случаях.
Одним из важных преимуществ инициализации вызова функции является то, что они также работают с конструкторами, которые принимают несколько аргументов. Например, конструктор fstream может принимать два параметра:
std::fstream file("filename", ios_base::out);
До тех пор, пока унифицированная инициализация C++0x не станет широко доступной, инициализация вызова функции является единственным способом обработки конструкторов с несколькими аргументами.
Насколько я понимаю, &var является псевдонимом для переменной var и не имеет значения, какой из них вы используете.
-------- Дополнение -----------------
Приведенный ниже код взят из книги Страуструпа. Из этого ясно, что оба являются псевдонимами одной и той же переменной. Это также говорит как ниже.
"Семантика передачи аргументов определяется как инициализация, поэтому при вызове аргумент приращения aa становится другим именем x". Вот почему я назвал &x псевдонимом x.
void increment(int& aa) { aa++; }
void f() { int x = 1; increment(x); }