| HTML [44] |
| Visual C++ и MFC [21] |
| c++ [78] |
| php [19] |
| Javascript [15] |
| C# [51] |
| загрузки [0] |
|
XNA [10]
создание игр с помощью xna
|
| Главная » Статьи » c++ |
Ну что ж, приступим! Сконцетрируйтесь, закройте глаза. Подумайте о чем-то хорошем. Я надеюсь, Вы подумали о С++. Отдохнули? Продолжаем наше погружение в прекрасный мир совершенного языка. По крайней мере, некоторые так думают. По умолчанию, при инициализации одного объекта другим, С++ выполняет побитовое копирование (почленное копирование). Сильно сказано. Это означает, что один объект становится точной копией другого. Продемонстрируем всё вышесказанное на примере: #include<iostream.h>
class A{
int a;
public:
void Set(int f){
a=f;
}
};
void main(){
A ist;
ist.Set(4);
A cpy=ist;//После выполнения этой строки cpy будет копией ist
}
Хотя в большинстве случаев в этом нет ничего страшного, существуют ситуации, когда побитовое копирование не должно использоваться. Например, когда объект выделяет память при своем создании: ПримерПусть у нас есть 2 обьекта G и J класса MyClass, выделяющего память при создании обьекта.Предположим, что обьект G уже существует. Это означает что обьект G уже выделил память. Далее предположим, что G использовался для инициализации обьекта J, как показано ниже: MyClass J=G; Если в данном случае используется побитовое копирование( почленное копирование). То J станет копией G. Это значит, что J будет использовать тот же участок выделенной памяти, что и G,вместо того, чтобы выделить свой. Это чрезвычайно плохо. Если например в классе MyClass есть деструктор, освобождающий память, то тогда одна и та же память будет очищена дважды при уничтожении G и J. #include<iostream.h>
// Реализация описанного выше
class MyClass{
public:
int *x;
MyClass(){
x=new int;
}
~MyClass(){
delete x;
}
};
void main(){
// при создании обьекта G выделяется память в теле конструкторе
MyClass G;
// Вот-то и возникает проблема снова создаётся обьект,
// а память в конструкторе не выделяется.В итоге указатель
// J.x указывает в ту же область память ,что и G.x
MyClass J=G;
// при выходе из функции main 2 раза вызывается деструктор,
// который очищает память отведённую при создании обьекта
// то есть выполняется delete x для J и delete x для G
// а так как J.x=G.x то отсюда следует вывод, что 2 раза
// очищается одна и та же область памяти. Это повлечет за
// собой ошибку на этапе выполнения программы
}
Проблема того же типа может возникнуть ещё в 2х случаях. Первый из них возникает, когда обьекта передается по значению в функцию в качестве аргумента: #include<iostream.h>
class MyClass{
public:
int *x;
MyClass(){
x=new int;
}
~MyClass(){
delete x;
}
};
void f(MyClass d){
}
void main(){
// при создании обьекта G выделяется память в теле конструкторе
MyClass G;
// При передаче в функцию обьекта G по значению будет создана
// дополнительная копия обьекта.Это будет проделано с помощью
// побитового копирования (т.е. как обьяснялось выше память не будет
// выделена)
f(G);
}
Опять же возникнет ошибка на этапе выполнения программы !!!
Второй появляется , когда временный обьект создается
функцией возвращающей обьект в качестве своего значения.
Пример :
#include<iostream.h>
class MyClass{
public:
int *x;
MyClass(){
x=new int;
cout<<"It's me";
}
~MyClass(){
delete x;
}
};
MyClass f(){
MyClass s;
// та же ошибка!!! При возврате значения создаётся побитовая копия
// под которую не выделяется память
return s;
}
void main(){
f();
}конструктор копирования
Синтаксис конструктора копированияимя_класса(const имя_класса & W){
тело конструктора
}
Здесь W является ссылкой на обьект в правой части инициализации. Конструктор копирования может иметь также дополнительные параметры, если для них определены значения по умолчанию.Однако в любом случае первым параметром должна быть ссылка на объект выполняющий инициализацию. ПамяткаИнициализация возникает в 3х случаях.
Пример использования конструктора копирования.Эта программа создает простой класс «Безопасный массив». Поскольку место для массива выделено с помощью new, то для выделения памяти в случае, когда один обьект используется для инициализации другого,предоставляется конструктор копирования #include <iostream.h>
#include <stdlib.h>
// В классе array будет переменная указатель,переменная, отвечающая
// за размер массива,конструктор копирования и 2 функции одна
// для инициализации массива, другая для возврата i-го элемента
class array{
int *p;
int size;//размер массива
public:
array(int s){//конструктор
p=new int[s];//выделение памяти под массив
size=s;//Если все нормально то запоминаем размер массива
}
//конструктор копирования
array(const array &d);
//инициализация массива
void Put(int i,int j){
if((i>=0)&&(i<size))// проверка на выход за границу массива
p[i]=j;
}
//получение i-го элемента
int Get(int i){
return p[i];
}
};
// тело конструктора копированяи
array::array(const array &f){
int i;
p=new int[f.size];//выделение памяти
if(!p)
exit(1);
for(i=0;i<f.size;i++)
p[i]=f.p[i]; //заполнение элементами из переданного массива
}
void
main(){
array n(10);//создание обьекта класса array
int i;
for(i=0;i<10;i++)n.Put(i,i);//Заполнение исходного массива
for(i=9;i>=0;i--)cout<<n.Get(i);//Вывод на экран исходного массива
cout<<endl;
// создание нового обьекта и инициализация его уже существующим
// в этой строке происходит вызов конструктора копирования в качестве параметра
// ему передается n.
array x=n;
// Вывод на экран содержимого массива нового обьекта.
for(i=0;i<10;i++)cout<<x.Get(i);
} | |
| Просмотров: 8709 | Рейтинг: 3.7/3 |
| Всего комментариев: 0 | |