Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ - [19]
Сгенерированный компилятором оператор присваивания для класса Named-Object
Например, предположим, что класс NamedObject определен, как показано ниже. Обратите внимание, что nameValue – ссылка на string, а objectValue имеет тип const T:
>template
>class NamedObject {
>public:
>// этот конструктор более не принимает const name, поскольку nameValue –
>// теперь ссылка на неконстантную строку. Конструктор с аргументом типа
>// char* исключен, поскольку нам нужна строка, на которую можно сослаться
>NamedObject(std::string& name, const T& value);
>... // как и ранее, предполагаем,
>// что operator= не объявлен
>private:
>std::string& nameValue; // теперь это ссылка
>const T objectValue; // теперь const
>};
Посмотрим, что произойдет в приведенном ниже коде:
>std::string newDog(“Persephone”);
>std::string oldDog(“Satch”);
>NamedObject
>// наша собака Персефона собиралась
>// встретить свой второй день рождения
>NamedObject
>// детства) было бы теперь 36 лет
>p = s; // Что должно произойти
>// с данными-членами p?
Перед присваиванием и p.nameValue, и s.nameValue ссылались на объекты string, хотя и на разные. Что должно произойти с членом p.nameValue в результате присваивания? Должен ли он ссылаться на ту же строку, что и s.nameValue, то есть должна ли модифицироваться ссылка? Если да, это подрывает основы, потому что C++ не позволяет изменить объект, на который указывает ссылка. Но, быть может, должна модифицироваться строка, на которую ссылается член p.nameValue, и тогда будут затронуты другие объекты, содержащие указатели или ссылки на эту строку, хотя они и не участвовали непосредственно в присваивании? Это ли должен делать сгенерированный компилятором оператор присваивания?
Сталкиваясь с подобной головоломкой, C++ просто отказывается компилировать этот код. Если вы хотите поддерживать присваивание в классе, включающем в себя член-ссылку, то должны определить оператор присваивания самостоятельно. Аналогичным образом компилятор ведет себя с классами, содержащими константные члены (такие как objectValue во втором варианте класса NamedObject выше). Модифицировать константные члены запрещено, поэтому компилятор не знает, как поступать при неявной генерации оператора присваивания. Кроме того, компилятор не станет неявно генерировать оператор присваивания в производном классе, если в его базовом объявлен закрытый оператор присваивания. И наконец, предполагается, что сгенерированные компилятором операторы присваивания для производных классов должны обрабатывать части базовых классов (см. правило 12), но при этом они конечно же не могут вызывать функции-члены, доступ к которым для них запрещен.
• Компилятор может неявно генерировать для класса конструктор по умолчанию, конструктор копирования, оператор присваивания и деструктор.
Правило 6: Явно запрещайте компилятору генерировать функции, которые вам не нужны
Агенты по продаже недвижимости и программные системы, обслуживающие их деятельность, могут нуждаться в классе, представляющем дома, выставленные на продажу:
>class HomeForSale {...};
Любой агент по продаже недвижимости скажет вам, что каждый объект уникален – не бывает двух, в точности одинаковых. Вот почему идея создания копии объекта HomeForSale бессмысленна. Как можно скопировать нечто, по определению, уникальное? Поэтому хотелось бы, чтобы попытки скопировать объекты HomeForSale не компилировались:
>HomeForSale h1;
>HomeForSale h2;
>HomeForSale h3(h1); // попытка скопировать h1 –
>// не должно компилироваться!
>h1 = h2; // попытка скопировать h2 –
>// не должно компилироваться!
Увы, предотвратить такую компиляцию не так-то просто. Обычно, если вы не хотите, чтобы класс поддерживал определенного рода функциональность, вы просто не объявляете функций, которые ее реализуют. Но с конструктором копирования и оператором присваивания эта стратегия не работает, поскольку, как следует из правила 5, если вы их не объявляете, а где-то в программе производится попытка их вызвать, то компилятор сгенерирует их автоматически.
Похоже на безвыходное положение. Если вы сами не объявите конструктор копирования или оператор присваивания, то их сгенерирует компилятор. И ваш класс будет поддерживать копирование. Но то же самое произойдет, если вы объявите эти функции самостоятельно. Однако наша цель – предотвратить копирование!
Ключ к решению в том, что все сгенерированные компилятором функции являются открытыми. Чтобы предотвратить автоматическое генерирование, вы должны объявить их самостоятельно, но никто не требует, чтобы они были открытыми. Ну так и объявите конструктор копирования и оператор присваивания закрытыми. Объявляя явно функцию-член, вы предотвращаете генерирование ее компилятором, а сделав ее закрытой, не позволяете кому-либо вызывать ее.
Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.
Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.
Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.