C++ 中构造函数的实例详解

2020-01-06 17:27:18于海丽

下面使用上面定义的类对象来说明各个构造函数的用法:


void main()
{
  // 调用了无参构造函数,数据成员初值被赋为0.0
  Complex c1,c2;
 
  // 调用一般构造函数,数据成员初值被赋为指定值
  Complex c3(1.0,2.5);
  // 也可以使用下面的形式
  Complex c3 = Complex(1.0,2.5);
     
  // 把c3的数据成员的值赋值给c1
  // 由于c1已经事先被创建,故此处不会调用任何构造函数
  // 只会调用 = 号运算符重载函数
  c1 = c3;
     
  // 调用类型转换构造函数
  // 系统首先调用类型转换构造函数,将5.2创建为一个本类的临时对象,然后调用等号运算符重载,将该临时对象赋值给c1
  c2 = 5.2;
    
  // 调用拷贝构造函数( 有下面两种调用方式) 
  Complex c5(c2);
  Complex c4 = c2; // 注意和 = 运算符重载区分,这里等号左边的对象不是事先已经创建,故需要调用拷贝构造函数,参数为c2    
     
}

3. 思考与测验

(1) 为什么函数中可以直接访问对象c的私有成员 ?


Complex(const Complex & c)
{
  // 将对象c中的数据成员值复制过来
  m_real = c.m_real;
  m_img = c.m_img;
}

(2) 挑战题,了解引用与传值的区别


Complex test1(const Complex& c)
{
  return c;
}
  
Complex test2(const Complex c)
{
  return c;
}
  
Complex test3()
{
  static Complex c(1.0,5.0);
  return c;
}
  
Complex& test4()
{
  static Complex c(1.0,5.0);
  return c;
}
  
void main()
{
  Complex a,b;
  
  // 下面函数执行过程中各会调用几次构造函数,调用的是什么构造函数?
   
  test1(a);
  test2(a);
   
  b = test3();
  b = test4();
   
  test2(1.2);
   
  // 下面这条语句会出错吗?
  test1(1.2);   
   
  //test1( Complex(1.2 )) 呢?
}

4. 浅拷贝与深拷贝

上面提到,如果没有自定义复制构造函数,则系统会创建默认的复制构造函数,但系统创建的默认复制构造函数只会执行“浅拷贝”,即将被拷贝对象的数据成员的值一一赋值给新创建的对象,若该类的数据成员中有指针成员,则会使得新的对象的指针所指向的地址与被拷贝对象的指针所指向的地址相同,delete该指针时则会导致两次重复delete而出错。下面是示例:


#include <iostream.h>
#include <string.h>
class Person 
{
public :
     
  // 构造函数
  Person(char * pN)
  {
    cout << "一般构造函数被调用 !n";
    m_pName = new char[strlen(pN) + 1];
    //在堆中开辟一个内存块存放pN所指的字符串
    if(m_pName != NULL) 
    {
      //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
       strcpy(m_pName ,pN);
    }
  }    
    
  // 系统创建的默认复制构造函数,只做位模式拷贝
  Person(Person & p)  
  { 
    //使两个字符串指针指向同一地址位置     
    m_pName = p.m_pName;     
  }
 
  ~Person( )
  {
    delete m_pName;
  }
     
private :
  char * m_pName;
};
 
void main( )
{ 
  Person man("lujun");
  Person woman(man); 
   
  // 结果导致  man 和  woman 的指针都指向了同一个地址
   
  // 函数结束析构时
  // 同一个地址被delete两次
}
 
 
// 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
Person(Person & chs);
{
   // 用运算符new为新对象的指针数据成员分配空间
   m_pName=new char[strlen(p.m_pName)+ 1];
 
   if(m_pName)     
   {
       // 复制内容
      strcpy(m_pName ,chs.m_pName);
   }
  
  // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
}