Site Tools


c_specialmemberfunctions

справочник IBM
MSDN таблица свойств

Общая информация

Правило трёх (также известное как «Закон Большой Тройки» или «Большая Тройка») правило в C++, гласящее, что если класс или структура определяет один из следующих методов, то они должны явным образом определить все три метода:

  • Деструктор
  • Конструктор копирования
  • Оператор присваивания копированием
когда следует определять?

В случаях, когда:

  • класс инкапсулирует сложные структуры данных (указатели, массивы)
  • может поддерживать эксклюзивный доступ к ресурсам
  • класс содержит константные данные или ссылки. (TODO: уточнить)

Оператор присвоения

вызывается в случае

obj1 = obj2
obj1 = obj1 //самокопирование
A a2;
B b;
a2 = b;    // Шаг1: создается временный объект класса а A
           // с помощью конструктора вида A(b),
           // Шаг2: -> operator=(const A&) то есть operator=(A(b))

Не вызывается в случае (вызывается конструктор копирования)

MyClass obj1 = obj2
MyClass obj1 = MyClass(obj2)

Требования

В операторе присвоения следует проверять самокопирование (&copy == this) и если объект копирует сам себя (obj1 = obj1) принимать соответствующие действия.
по соглашению, всегда возвращаем *this.
Это необходимо для следующий конструкции array_1 = array_2 = array_3;

Пример

MyClass& operator = (const MyClass &copy){
	if(&copy != this){
	i = copy.i;
	iMass = new int[copy.i];
	std::copy(copy.iMass, copy.iMass + copy.i, iMass);
	cout << "operator = " << endl;
	}
      // по соглашению всегда возвращаем *this
      return *this;
}

Конструктор копирования

MyClass(const MyClass &copy){/*реализация*/}

Вызывается в случае инициализаций

MyClass obj3 = obj1;
MyClass obj3(obj1);
MyClass obj3 = MyClass(obj1);
A a2;
B b;
a2 = b;    // Шаг1: создается временный объект класса а A
           // с помощью конструктора вида A(b),
           // Шаг2: -> operator=(const A&) то есть operator=(A(b))

Требования

  • в качестве параметра обязательно должна передаваться по ссылки (без копирования) (TODO: по указателю можно?), иначе, копия объекта будет рекурсивно замкнута.
  • как и любой конструктор, не возвращает данные.

Пример

MyClass(const MyClass &copy) : i(copy.i), iMass(new int[copy.i]){
	std::copy(copy.iMass, copy.iMass + copy.i, iMass);
	cout << "copy constructor" << endl;
}
Какой конструктор будет вызван?
...
MyClass(const MyClass &copy) : i(copy.i), iMass(new int[copy.i]){
	std::copy(copy.iMass, copy.iMass + copy.i, iMass);
	cout << "constantant copy constructor" << endl;
}
MyClass(MyClass &copy) : i(copy.i), iMass(new int[copy.i]){
	std::copy(copy.iMass, copy.iMass + copy.i, iMass);
	cout << "NO constant copy constructor" << endl;
}
...
main(){
		MyClass obj1;
...  
	MyClass const obj3 = obj1; // NO const copy constructor
	MyClass obj4(obj3); // copy constructor
}

Общие примеры

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;

class MyClass{
public:
	int i;
	int *iMass;
	MyClass(const int inI) : i(inI), iMass(new int[i]){}
	MyClass(const MyClass &copy) : i(copy.i), iMass(new int[copy.i]){ //конструктор копирования
		std::copy(copy.iMass, copy.iMass + copy.i, iMass);
		cout << "copy constructor" << endl;
	}
	~MyClass(){
		delete[] iMass;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{

	MyClass obj1(3);
	MyClass obj2(4);

	obj1.iMass[0] = 4;
	obj1.iMass[1] = 6;
	obj1.iMass[2] = 8;

	cout << "obj1: ";
	for(int i = 0; i < 3; i++){
		cout << obj1.iMass[i] << " ";
	}
	cout << endl;

	{
		MyClass obj3(obj1);
		cout << "obj3 after copyConstructor: ";
		for(int i = 0; i < 3; i++){
			cout << obj3.iMass[i] << " ";
		}
		cout << endl;
	}

	cout << "obj1 after delete obj3: ";
	for(int i = 0; i < 3; i++){
		cout << obj1.iMass[i] << " ";
	}
	cout << endl;

	string endString;
	cin >> endString;
	return false;
}

вывод

obj1: 4 6 8
copy constructor
obj3 after copyConstructor: 4 6 8
obj1 after delete obj3: 4 6 8

если заккоментировать код конструктора копирования, то вывод будет:

obj1: 4 6 8
obj3 after copyConstructor: 4 6 8
obj1 after delete obj3: -17891602 -17891602 -17891602

так как, указатель(массив) iMass будет скопировал конструктором по умолчания как ссылка и разрушен деструктором.

Так же и с оператором присвоения:

int operator = (const MyClass &copy){
	i = copy.i;
	iMass = new int[copy.i];
	std::copy(copy.iMass, copy.iMass + copy.i, iMass);
	cout << "operator = " << endl;
	return 1;
}

иначе конструкция obj3 = obj1; выполнит реализацию по умолчанию и так же произведет копирование адреса указателя.

Конструктор преобразования

Это конструктор имеющий один аргумент. Позволяет использовать неявное преобразование типов, к примеру:

class A;
class B;
B objB;
f(A obj){\*реализация*\}

f(objB);

Данная конструкция будет позволительна, если в классе A есть конструктор преобразования:

class A{
public:
    A(const B &b){\*реализация*\}
}

В этом случае, f(objB) будет неявно преобразовано к f(A(objB));

методы преобразования

Помимо конструктора, используеются методы (?для обратного преобразования):

MyClass(OtherClass &b){} //пример выше
operator int(){}
operator double(){}

Пример метода преобразования

источник
Использование при преобразование объекта к int

  class Y {
    int b;
  public:
    Y(const int xIn):b(xIn){};
    operator int(){return b;}
  };
  
  int _tmain(int argc, _TCHAR* argv[])
  {
     Y testInt(13);
     Y test2Int(7);
     int i = int(testInt);
     cout << "i=" << i;
     int p = testInt;
     cout << " p=" << p;
     int j = (int)testInt;
     cout << " j=" << j;
     int k = i + testInt;
     cout << " k=" << k;
     int l = test2Int + testInt;
     cout << " l=" << l << endl;
  }

вывод

  i=13 p=13 j=13 k=26 l=20
You could leave a comment if you were logged in.
c_specialmemberfunctions.txt · Last modified: 2013/04/11 01:38 by konovalov

Page Tools