» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

На нашем литературном портале можно бесплатно читать книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, Бьёрн Страуструп . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале litmir.org.
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Название: Программирование. Принципы и практика использования C++ Исправленное издание
Дата добавления: 22 август 2024
Количество просмотров: 99
Читать онлайн

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту readbookfedya@gmail.com для удаления материала

Программирование. Принципы и практика использования C++ Исправленное издание читать книгу онлайн

Программирование. Принципы и практика использования C++ Исправленное издание - читать бесплатно онлайн , автор Бьёрн Страуструп

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка.
Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие.
Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток.
Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Перейти на страницу:
принципе без конструктора мы не можем установить инвариант, поскольку не можем гарантировать, что его объекты будут корректными (см. раздел 9.4.3). Мы настаиваем на том, что такие переменные должны быть проинициализированы. В таком случае фрагмент можно было бы переписать следующим образом:

string s1 = "";

vector<string> v1(0);

vector<string> v2(10,""); // вектор, содержащий 10 пустых строк

Однако этот код не кажется нам таким уж хорошим. Для объекта класса string строка "" является очевидным обозначением пустой строки, а для объекта класса vector легко догадаться, что число 0 означает пустой вектор. Однако для многих типов правильно интерпретировать значение, заданное по умолчанию, совсем не так легко. В таких случаях лучше было бы определить конструктор, создающий объект без использования явной инициализации. Такие конструкторы не имеют аргументов и называются конструкторами по умолчанию.

Для дат не существует очевидного значения, заданного по умолчанию. По этой причине мы до сих пор не определяли для класса Date конструктор по умолчанию, но сейчас сделаем это (просто, чтобы показать, что мы можем это сделать).

class Date {

public:

  // ...

  Date(); // конструктор по умолчанию

  // ...

private:

  int y;

  Month m;

  int d;

};

Теперь мы должны выбрать дату, заданную по умолчанию. Для этого вполне подходит первый день XXI столетия.

Date::Date()

     :y(2001), m(Date::jan), d(1)

{

}

 

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

const Date& default_date()

{

  static Date dd(2001,Date::jan,1);

  return dd;

}

Здесь использовано ключевое слово static, чтобы переменная dd создавалась только один раз, а не каждый раз при очередном вызове функции default_date(). Инициализация этой переменной происходит при первом вызове функции default_date(). С помощью функции default_date() легко определить конструктор, заданный по умолчанию, для класса Date.

Date::Date()

     :y(default_date().year()),

      m(default_date().month()),

      d(default_date().day())

}

Обратите внимание на то, что конструктор по умолчанию не обязан проверять значение, заданное по умолчанию; конструктор, создавший объект, вызвавший функцию default_date, уже сделал это. Имея конструктор для класса Date по умолчанию, мы можем создать векторы объектов класса Date.

vector<Date> birthdays(10);

Без конструктора по умолчанию мы были бы вынуждены сделать это явно.

vector<Date> birthdays(10,default_date());

9.7.4. Константные функции-члены

Некоторые переменные должны изменяться, потому они так и называются, а некоторые — нет; иначе говоря, существуют переменные, которые не изменяются. Обычно их называют константами, и для них используется ключевое слово const. Рассмотрим пример.

void some_function(Date& d, const Date& start_of_term)

{

  int a = d.day();             // OK

  int b = start_of_term.day(); // должно бы правильно (почему ?)

  d.add_day(3);                // отлично

  start_of_term.add_day(3);    // ошибка

}

Здесь подразумевается, что переменная d будет изменяться, а переменная start_of_term — нет; другими словами, функция some_function() не может изменить переменную start_of_term. Откуда компилятору это известно? Дело в том, что мы сообщили ему об этом, объявив переменную start_of_term константой (const). Однако почему же с помощью функции day() можно прочитать переменную day из объекта start_of_term? В соответствии с предыдущим определением класса Date функция start_of_term.day() считается ошибкой, поскольку компилятор не знает, что функция day() не изменяет свой объект класса Date. Об этом в программе нигде не сказано, поэтому компилятор предполагает, что функция day() может модифицировать свой объект класса Date, и выдаст сообщение об ошибке.

 

 Решить эту проблему можно, разделив операции над классом, на модифицирующие и немодифицирующие. Это не только помогает понять суть класса, но и имеет очень важное практическое значение: операции, которые не модифицируют объект, можно применять к константным объектам. Рассмотрим пример.

class Date {

public:

  // ...

  int day() const;       // константный член: не может изменять

                         // объект

  Month month() const;   // константный член: не может изменять

                         // объект 

 int year() const;       // константный член: не может изменять

                         // объект

  void add_day(int n);   // неконстантный член: может изменять

                         // объект

  void add_month(int n); // неконстантный член: может изменять

                         // объект

  void add_year(int n);  // неконстантный член: может изменять

                         // объект

private:

  int y; // год

  Month m;

  int d; // день месяца

};

Date d(2000, Date::jan, 20);

const Date cd(2001, Date::feb, 21);

cout << d.day() << " — " << cd.day() << endl; // OK

d.add_day(1);  // OK

cd.add_day(1); // ошибка: cd — константа

Ключевое слово const в объявлении функции-члена стоит сразу после списка аргументов, чтобы обозначить, что эту функцию-член можно вызывать для константных объектов. Как только мы объявили функцию-член константной, компилятор берет с нас обещание не модифицировать объект. Рассмотрим пример.

int Date::day() const

{

  ++d; // ошибка: попытка изменить объект в константной

       // функции - члене

  return d;

}

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

9.7.5. Члены и вспомогательные функции

 

 Разрабатывая минимальный (хотя и полный) интерфейс, мы вынуждены оставлять за бортом много полезных операций. Функцию, которая могла бы быть просто, элегантно и эффективно реализована как самостоятельная функция (т.е. не функция-член), следует реализовать за пределами класса. Таким образом, функция не сможет повредить данные, хранящиеся в объекте класса. Предотвращение доступа к данным является важным фактором, поскольку обычные методы поиска ошибок “вращаются вокруг типичных подозрительных мест”; иначе говоря, если с классом что-то не так, мы в первую очередь проверяем функции, имеющие прямой доступ к его представлению: одна из них обязательно является причиной ошибки. Если таких
Перейти на страницу:
Комментариев (0)