C++拷贝构造函数

C++拷贝构造函数

1 引入拷贝构造函数

对象赋值语句:就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。
C++支持两种初始化形式:

拷贝初始化 int a = 5; 和直接初始化 int a(5); 对于其他类型没有什么区别,对于类类型直接初始化直接调用实参匹配的构造函数,拷贝初始化总是调用拷贝构造函数,也就是说:

A x(2);  //直接初始化,调用构造函数
A y = x;  //拷贝初始化,调用拷贝构造函数

必须定义拷贝构造函数的情况:

只包含类类型成员或内置类型(但不是指针类型)成员的类,无须显式地定义拷贝构造函数也可以拷贝;有的类有一个数据成员是指针,或者是有成员表示在构造函数中分配的其他资源,这两种情况下都必须定义拷贝构造函数。

2 拷贝构造函数的定义及其作用

拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用。

(它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。)

其作用是:使用一个已经存在的对象去初始化另一个同类的对象。

3 拷贝构造函数的结构

classname (const classname &obj) {
   // 构造函数的主体
}

obj 是一个对象引用,该对象是用于初始化另一个对象的。

4 拷贝构造函数的特点

(1) 因为该函数也是一种构造函数,所以其函数名与类名相同,并且该函数也没有返回值类型。
(2) 该函数一般只有一个参数,并且是同类对象的引用。
(3) 每个类都必须有一个拷贝构造函数。程序员可以根据需要定义特定的拷贝构造函数,以实现同类对象之间数据成员的传递。如果程序员没有定义类的拷贝构造函数,系统就会自动生成产生一个缺省的拷贝构造函数。

例一:

#include <iostream>

using namespace std;

class Line
{
public:
    int getLength(void);
    Line(int len);             // 简单的构造函数
    Line(const Line& obj);      // 拷贝构造函数
    ~Line();                     // 析构函数

private:
    int* ptr;
};

// 成员函数定义,包括构造函数
Line::Line(int len)
{
    cout << "调用构造函数" << endl;
    // 为指针分配内存
    ptr = new int;
    *ptr = len;
}

Line::Line(const Line& obj)
{
    cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
    ptr = new int;
    *ptr = *obj.ptr; // 拷贝值
}

Line::~Line(void)
{
    cout << "释放内存" << endl;
    delete ptr;
}
int Line::getLength(void)
{
    return *ptr;
}

void display(Line obj)
{
    cout << "line 大小 : " << obj.getLength() << endl;
}

// 程序的主函数
int main()
{
    Line line1(10);

    Line line2 = line1; // 这里也调用了拷贝构造函数

    display(line1);
    display(line2);

    return 0;
}

运行结果:

调用构造函数
调用拷贝构造函数并为指针 ptr 分配内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
释放内存
释放内存

对以上程序稍作修改,通过使用已有的同类型的对象来初始化新创建的对象:
例二:

#include <iostream>
 
using namespace std;
 
class Line
{
   public:
      int getLength( void );
      Line( int len );             // 简单的构造函数
      Line( const Line &obj);      // 拷贝构造函数
      ~Line();                     // 析构函数
 
   private:
      int *ptr;
};
 
// 成员函数定义,包括构造函数
Line::Line(int len)
{
    cout << "调用构造函数" << endl;
    // 为指针分配内存
    ptr = new int;
    *ptr = len;
}
 
Line::Line(const Line &obj)
{
    cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
    ptr = new int;
    *ptr = *obj.ptr; // 拷贝值
}
 
Line::~Line(void)
{
    cout << "释放内存" << endl;
    delete ptr;
}
int Line::getLength( void )
{
    return *ptr;
}
 
void display(Line obj)
{
   cout << "line 大小 : " << obj.getLength() <<endl;
}
 
// 程序的主函数
int main( )
{
   Line line1(10);
 
   Line line2 = line1; // 这里也调用了拷贝构造函数
 
   display(line1);
   display(line2);
 
   return 0;
}

运行结果:

调用构造函数
调用拷贝构造函数并为指针 ptr 分配内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
调用拷贝构造函数并为指针 ptr 分配内存
line 大小 : 10
释放内存
释放内存
释放内存

例三:

#include<iostream>
using namespace std;

class Rect {

public:
    Rect(int w=13 , int h=14) //简单构造函数
    {
       
        width = w;
        height = h;
    }
    void print();
    Rect(const Rect& r);
private:
    int width;
    int height;
};
Rect::Rect(const Rect& r)
{
    width = r.width;
    height = r.height;
}

void Rect::print()
{
    cout << "width=" << width << "  ";
    cout << "height = " << height;
    cout << endl;
}
int main()
{
    Rect A;
    cout << "A:";
    A.print();
    cout << "B copy A: " << endl;
    Rect B(A);
    cout << "B:";
    B.print();
}

5 调用拷贝构造函数的3种情况

在C++中,下面三种情况需要调用拷贝构造函数!

对象需要通过另外一个对象进行初始化;
对象以值传递的方式传入函数参数
对象以值传递的方式从函数返回 

5.1对象需要通过另外一个对象进行初始化;

#include<iostream>
using namespace std;
class Point
{
public:
    Point(int a = 0, int b = 0)
    {
        x = a; y = b;
        cout << "Using normal constructor\n";
    }
    Point(const Point& p)
    {
        x = p.x;  y = p.y;
        cout << "Using copy constructor\n";
    }
    void print()
    {
        cout << x << "  " << y << endl;
    }
private:
    int x, y;
};

int main()
{
    Point p1(985, 211);
    p1.print();

    Point p2(p1);//对象需要通过另外一个对象进行初始化
    p2.print();

    Point p3 = p1;//对象需要通过另外一个对象进行初始化
    p3.print();

    return 0;
}

Using normal constructor
985  211
Using copy constructor
985  211
Using copy constructor
985  211

5.2对象以值传递的方式传入函数参数

#include<iostream>
using namespace std;
class Point
{
public:
    Point(int a = 0, int b = 0)
    {
        x = a;
        y = b;
        cout << "Using normal constructor\n";
    }
    Point(const Point& p)
    {
        x = p.x;
        y = p.y;
        cout << "Using copy constructor\n";
    }
    void print()
    {
        cout << x << "  " << y << endl;
    }
private:
    int x, y;
};
void fun1(Point p) { 
    p.print();
}

int main()
{
    Point p1(66,99);
    fun1(p1);
    return 0;
}


运行结果:

Using normal constructor
Using copy constructor
66  99

5.3对象以值传递的方式从函数返回

#include<iostream>
using namespace std;
class Point
{
public:
    Point(int a = 0, int b = 0)
    {
        x = a;
        y = b;
        cout << "Using normal constructor\n";
    }
    Point(const Point& p)
    {
        x = p.x;
        y = p.y;
        cout << "Using copy constructor\n";
    }
    void print()
    {
        cout << x << "  " << y << endl;
    }
private:
    int x, y;
};

Point fun2() // 类名 方法名
{
    Point p4(33, 15);
    return p4;
}


int main()
{
    Point p;    //定义对象
    p = fun2(); //对象以值传递的方式从函数返回
    p.print();
    return 0;
}

思考:为什么出现两次Using normal constructor?

Using normal constructor
Using normal constructor
Using copy constructor
33  15

最后一例子:

#include <iostream>
using namespace std;
class CExample
{
private:
    int a;

public:
    //构造函数
    CExample(int b)
    {
        a = b;
        cout << "creat a= " << a << endl;
    }

    //拷贝构造
    CExample(const CExample& C)
    {
        a = C.a;
        cout << "\nUsing copy constructor\n " << endl;
    }
   
    //析构函数
    ~CExample()
    {
        cout << "delete: " << a << endl;
    }

    void Show()
    {
        cout << "copy a= " << a << endl;
    }
};

//全局函数,传入的是对象
void g_Fun(CExample C)
{
    C.Show();
   
}

int main()
{
    CExample test(10);
    //传入对象
    g_Fun(test);

   // test.Show();   

    return 0;
}

提问:如果把去掉 // test.Show();的注释,结果会如何?为什么?构造函数和析构函数的执行顺序如何?欢迎评论!
图一:
在这里插入图片描述
图二:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值