1. 构造函数
   
    构造函数是成员函数的一种。名字与类名相同,可以有参数,但
    
     不能有返回值(void 也不行)。
    
   
    
     构造函数的作用是对对象进行初始化,如给成员变量赋初值。
    
   
编译器生成的默认构造函数无参数,不做任何操作。
    
     对象生成时构造函数自动被调用。
    
    对象一旦生成,就再也不能在其上执行构造函数。一个类可以有多个构造函数。
   
    
     构造函数的意义:
    
   
- 自动初始化对象,不再需要额外初始化对象。(不必专门再编写初始化函数,不用担心忘记调用初始化函数。)
 - 避免无初始化导致的未知错误。(对象需先初始化再被使用。对象没被初始化就被使用,会导致程序出错。)
 
    
     构造函数基本使用
    
   
class Complex {
    double real, imag;  // private
public:
    Complex(double r, double i=0);
};
Complex::Complex(double r, double i)
{
    real = r;
    imag = i;
}
Complex c1; //error。缺少构造函数的参数
Complex * pc = new Complex; //error。缺少构造函数的参数
Complex c1(2);  //ok
Complex c1(2,4),c2(3,5);
Complex * pc = new Complex(3,4);  
#include<iostream>
class Complex {
    double real, imag;  // private
public:
    Complex(double r, double i);
    Complex(double r);
    Complex(Complex c1, Complex c2);          //多个构造函数是重载关系
};
Complex::Complex(double r, double i)
{
    real = r;
    imag = i;
}
Complex::Complex(double r)
{
    real = r;
    imag = 0;
}
Complex::Complex(Complex c1, Complex c2)
{
    real = c1.real + c2.real;   
    imag = c1.imag + c2.imag;   // 均合法,使用同类对象私有变量
}
int main()
{
    Complex a;      // 非法,无参缺省构造函数已停用
    Complex c1(4), c2(2, 1); // 自动转化为 double
    Complex c3(c1, c2);
    Complex * p = new Complex(1);
    return 0;
}
    
     构造函数与数组:
    
   
#include<iostream>
class Test {
public:
    int x;
    Test() 
    {
        std::cout << "Constructor 1 Called." << std::endl;
    }
    Test(int i)
    {
        x = i;
        std::cout << "Constructor 2 Called." << std::endl;
    }
};
int main()
{
    Test A[2];
    std::cout << "Step 1" << std::endl;
    Test B[2] = {4,5};        // A[1]只有一个空元素也要调用constructor
    std::cout << "Step 2" << std::endl;
    Test C[2] = {3};
    std::cout << "Step 3" << std::endl;
    Test * P = new Test[2];   // 这种初始化方式C++11才有,warning: 额外的初始化,new feature
    std::cout << "Step 4" << std::endl;
    delete []P;
  
    return 0;
}
    
     输出
    
   
Constructor 1 Called. 
Constructor 1 Called. 
Step 1 
Constructor 2 Called. 
Constructor 2 Called. 
Step 2 
Constructor 2 Called. 
Constructor 1 Called. 
Step 3 
Constructor 1 Called. 
Constructor 1 Called. 
Step 4
#include<iostream>
class Test {
public:
    int x;
    Test() 
    {
        std::cout << "Constructor 1 Called." << std::endl;
    }
    Test(int i)
    {
        x = i;
        std::cout << "Constructor 2 Called." << std::endl;
    }
    Test(int a, int b)
    {
        x = a + b;
        std::cout << "Constructor 3 Called." << std::endl;
    }
};
int main()
{
    Test A[3] = {1,Test{1,2}};        // 三个对象分别用(2),(3),(1)初始化
    std::cout << "Step 1" << std::endl;
    Test B[3] = {Test(2, 1),Test(2, 1), 5}; //三个对象分别用(3),(3),(2)初始化
    std::cout << "Step 2" << std::endl;
    Test * P[3] = {new Test(4), new Test(2,1)};   // p是指针数组,如果没有初始化将不会生成任何对象。
    //用new出来对象的地址来初始化指针。 只初始化两个对象,分别用(2),(3)
    std::cout << "Step 3" << std::endl;
    delete []P;
    Test * PA[3] = {new Test(1), new Test(1,2), NULL};  // PA[2]只有一个指针不调用constructor
    delete PA[1];
    delete PA[0];
    std::cout << "Step 4" << std::endl;
    return 0;
}
    
     输出:
    
   
Constructor 2 Called. 
Constructor 3 Called. 
Constructor 1 Called. 
Step 1 
Constructor 3 Called. 
Constructor 3 Called.
Constructor 2 Called. 
Step 2 
Constructor 2 Called. 
Constructor 3 Called. 
Step 3 
Constructor 2 Called. 
Constructor 3 Called. 
Step 4
    2. 复制构造函数
   
构造函数中的一种。
    
     只有一个参数,即对同类对象的引用(可以是
     
      const
     
     或非
     
      const
     
     ,一般使用
     
      const
     
     )形如:T :: T ( T & ) 或 T :: T (const T & )
    
   
编译器会自动生成复制构造函数,若程序员自己定义,则自动生成的复制构造函数不存在
    
     自动生成的复制构造函数:
    
   
#include<iostream>
class A {
public:
    int v;
    A(int i)
    {
        v = i;
    }
};
int main()
{
    A c1(5);
    A c2(c1);   // 缺省的复制构造函数被调用(未定义复制构造函数时)
    std::cout << c1.v << std::endl;
    std::cout << c2.v << std::endl;
    return 0;
}
    
     三种复制构造函数起作用的情况:
    
   
- 用一个对象初始化另一个同类的对象
 
#include<iostream>
class A {
public:
int v;
A(int i)
{
    v = i;
}
A(A & a)
{
    v = a.v;
    std::cout << "Copy constructor called." << std::endl;
}
};
int main()
{
A c1(5);
A c2(c1);   // 初始化,复制构造函数被调用
A c3 = c2;  // 同样是初始化语句,而非赋值语句,复制构造函数被调用
c1 = c2;    // 赋值语句,不调用复制构造函数
return 0;
}
- 如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。
 
#include<iostream>
class A {
public:
int v;
A(int i)
{
    v = i;
}
A(A & a)
{
    v = a.v;
    std::cout << "Copy constructor called." << std::endl;
}
};
void Fun(A a)
{
std::cout << a.v << std::endl;
}
int main()
{
A c1(5);
Fun(c1);    // 复制构造函数被调用形成形参
return 0;
}
//输出:
//Copy constructor called. 
//5
- 函数返回值为类的对象,函数返回时,该类的复制构造函数将被调用,初始化返回值
 
#include<iostream>
class A {
public:
int v;
A(int i)
{
    v = i;
}
A(const A & a)
{
    v = a.v;
    std::cout << "Copy constructor called." << std::endl;
}
};
A Fun(A a)
{
std::cout << a.v << std::endl;
return a;
}
int main()
{
A c1(5);
std::cout << Fun(c1).v << std::endl;    // 复制构造函数被调用形成形参,再被调用形成返回值
return 0;
}
输出:
Copy constructor called. 
5 
Copy constructor called. 
5
    
     Tips
    
   
- 对象间赋值并不导致复制构造函数被调用。
 - 
     使用
常量引用参数
,避免复制构造函数的调用开销,并避免在函数体内改变被引用的对象。 
void fun(const CMyclass & c){
    cout<<"fun"<<endl;
}
    3. 析构函数
   
- 
     名字与类名相同,在类名前加
‘
~'
符号 - 无参数和返回值
 - 
     
一个类最多拥有一个析构函数
 - 析构函数在对象消亡时被调用
 - 缺省的析构函数几乎不进行操作,程序员自定义后缺省的析构函数便消失。
 
    
     析构函数与数组,指针:
    
   
对象数组消亡时,每个对象的析构函数都会被调用
指针所指的动态分配的对象,不delete就不会消亡,也不调用析构函数(new 出来的对象,需使用 delete 才能调用析构函数使其消亡。)
若 new 一个对象数组,那么用 delete 释放时应该写 [ ] 。否则只 delete 一个对象(调用一次析构函数)。
Ctest * pTest;
pTest = new Ctest;  //构造函数调用
delete pTest;       //析构函数调用
pTest = new Ctest[3]; //构造函数调用3次
delete [] pTest;      //析构函数调用3次
    构造函数与析构函数调用的例子:
   
#include <iostream>
using namespace std;
class Demo{
	int id;
public:
	Demo(int i)
	{
		id = i;
		cout<<"id="<<id<<"constructed"<<endl;
	}
	~Demo()
	{
		cout<<"id="<<id<<"destructed"<<endl;
	}
};
Demo d1(1);  //全局变量。在main之前生成,调用构造函数。在main结束后消亡,调用析构函数。
void func()
{
	static Demo d2(2); //静态变量第一次初始化时需调用构造函数,在main结束后消亡,调用析构函数。
	Demo d3(3);         //函数结束就消亡,调用析构函数
	cout<<"func"<<endl;
}
int main()
{
	Demo d4(4);
	d4 = 6;                //调用类型转换构造函数,生成值为6的Demo类的临时对象,赋值后临时对象消亡,调用析构函数。
	cout<<"main"<<endl;
	{
		Demo d5(5);
	}
	func();
	cout<<"main end"<<endl;
	system("pause");
	return 0;
}
    
     输出:
    
   
id=1constructed
id=4constructed
id=6constructed
id=6destructed
main
id=5constructed
id=5destructed
id=2constructed
id=3constructed
func
id=3destructed
main end
id=6destructed
id=1destructed
id=2destructed