Среда, 08.01.2025, 20:56
Главная Регистрация RSS поиск
Приветствую Вас, Гость
Меню сайта
Категории раздела
HTML [44]
Visual C++ и MFC [21]
c++ [78]
php [19]
Javascript [15]
C# [51]
загрузки [0]
XNA [10]
создание игр с помощью xna
Наш опрос
Каким языком программирования вы увлекаетесь
Всего ответов: 2420
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Реклама
Главная » Статьи » 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х случаях.

  1. Когда один объект инициализирует другой,
  2. когда объект передаётся в функцию по значению и
  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);
 
}
Категория: c++ | Добавил: slava (30.05.2011)
Просмотров: 8659 | Рейтинг: 3.7/3
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]