拷贝构造函数

时间:2022-03-09 15:55:39

拷贝构造函数是与类名相同,形参是本类的对象的引用的函数。

类的拷贝构造函数一般由用户定义,如果用户没有定义构造函数,系统就会自动生成一个默认的函数,这个默认的拷贝构造函数的功能是把初始值对象的每个数据成员的值依次复制到新建立的对象中。

调用拷贝构造函数的三种情况:

1.使用类的一个对象去初始化另一个该类的对象

2.如果函数的形参是类的对象,调用函数时,将对象作为函数实参传递给函数的形参时

3.如果函数的返回值是类的对象,函数执行完成,将返回值返回。

举例说明:

#include <iostream>
using namespace std;
class Clock{
    private:
        int H,M,S;
    public:
        Clock(int h=0,int m=0,int s=0)
        {   
            H=h,M=m,S=s;
            cout << "constructor:"<<H<< ":"<<M<<":"<<S<<endl;
        }   
        ~Clock()
        {   
            cout << "destructor:"<<H<<":"<<M<<":"<<S<<endl;
        }   
        Clock(Clock &p) 
        {   
            cout << "copy constructor, vefore call:"<<H<<":"<<M<<":"<<S<<endl;
            H = p.H;
            M = p.M;
            S = p.S;
        }   
};
Clock fun(Clock C)
{
    return C;
}

int main()
{
    Clock C1(8,0,0);
    Clock C2(9,0,0);
    Clock C3(C1);
    fun(C2);
    Clock C4;
    C4 = C2;
}

运行结果

constructor:8:0:0
constructor:9:0:0
copy constructor, before call:-864987504:32767:4197058
copy constructor, before call:1:0:4197645
copy constructor, before call:-864987208:32767:4197552
destructor:9:0:0
destructor:9:0:0
constructor:0:0:0
destructor:9:0:0
destructor:8:0:0
destructor:9:0:0
destructor:8:0:0

结果分析

第一二行的结果是因为main函数中前两行的声明的C1和C2调用的构造函数

然后结果显示调用了三次拷贝构造函数,其分别是Clock C3(C1)调用了一次

fun(C2)调用了两次,分别是,C2作为参数,从实参到形参时调用了一次,和在fun函数返回时,返回值调用了一次

之后调用了两次析构函数,分别是C2作为参数,析构了一次,和返回值的析构

然后是C4的构造函数,最后是C4 C3 C2 C1的析构函数

===============================================================================================

今天在重看拷贝构造函数时,自己提出了一个问题,像上面的例子,在拷贝构造函数中,传入的对象我们可以用类如p.H  p.M这样的语句来访问,但是这些成员变量不都是私有的么,为什么可以这样访问呢?

下面一段话是对这个问题的解答;

仔细考究起来,我们其实可以这样看待类和对象:

类是将数据成员和进行于其上的一系列操作(成员函数)封装在一起,注意:成员函数可以操作数据成员(可以称类中的数据成员为泛数据成员)!

对象是类的实例化,怎样理解实例化?其实每一个实例对象都只是对其中的数据成员初始化,内存映像中每个对象仅仅保留属于自己的那份数据成员副本。而成员函数对于整个类而言却是共享的,即一个类只保留一份成员函数。

那么每个对象怎样和这些可以认为是分离的成员函数发生联系,即成员函数如何操作对象的数据成员?记住this指针,无论对象通过(.)操作或者(->)操作调用成员函数,编译时刻,编译器都会将这种调用转换成我们常见的全局函数的形式,并且多出一个参数(一般这个参数放在第一个),然后将 this指针传入这个参数。于是就完成了对象与成员函数的绑定(或联系).

实例化后就得到同一个类的多个不同的对象,既然成员函数共享的,那么成员函数就可以操作对象的数据成员。

问题是现在有多个对象,成员函数需要知道操作的是哪个对象的数据成员?

比如有对象obj1obj2,都属于A类,A类有public成员函数foo()

如果obj1调用该函数,编译时会给foo函数传入this指针,obj1,foo中操作obj1自身的成员就不用任何修饰,直接访问,因为其中的数据成员自动根据this指针找到。

如果obj1调用该函数,同样可以访问同类的其他对象的数据成员!那么你需要做的是让foo函数知道是同类对象中哪个对象的数据成员,一个解决办法是传入同类其他对象的指针或引用,那么就可以操作同类其他对象的数据成员。

foo(A &obj)

这样定义,然后调用:

obj1.foo(obj2)

就可以在obj1访问obj2的数据成员,而无论这些数据成员是private还是protected

也就是说,在C++中类中的几种属性是针对于类来说的,而不针对与对象。只要是在成员方法中,无论是不是操作的同一个对象,只要是从同一个类声明出来的对象,就都可以操作,不用考虑是不是私有或者保护类型。