精华内容
下载资源
问答
  • 拷贝构造函数和重载赋值运算符的区别
    2021-05-22 12:22:49

    其实自己对这两个区别是一直不怎么弄懂的,而且也曾经问过别人是怎么一个区别,不过人家说叫我看一下书,可惜的是最后还是没有弄懂。

    一直到昨天,考C++的时候,我似乎突然觉得明白了什么,于是就构思了一个测试的程序来看一下自己的猜想是否正确,现在实现以下,觉得已经能够明白了他们之间的却别了。

    记得当初我是这么问别人的:有了拷贝构造函数,就可以b =

    a;也没有错了,那么还要重载赋值运算符干嘛?两个有什么区别吗?其实当时他们是叫我去看一下拷贝构造函数的概念,结果我居然忘记了(其实很正常,因为记性越来越差了都)。

    为了测试到底有什么区别,我写了下面的一个测试程序:

    class A{

    public:

    A(){cout << "Structor!" <<

    endl;}

    A(A & a){cout << "Copy!" <<

    endl;}

    };

    int main()

    {

    A a, b = a;

    b = a;

    return 0;

    }

    结果发现输出是:

    Structor!

    Copy!

    如果把 A a, b = a;改为: A a, b;

    然后输出是:

    Structor!

    Structor!

    这样其实就可以看出到底是怎么样的一个情况:

    其实不管有没有拷贝构造函数,b =

    a;都没有错,因为系统会自动生成一个默认的拷贝构造函数,而有了拷贝构造函数的话,赋值语句b =

    a;还是调用系统默认的拷贝构造函数。

    而且我们应该还注意到的一个问题就是:拷贝构造函数的定义是说用一个对象去初始化同类的另一个对象的情况,注意到是初始化而不是其他的,所以这就是区别所在。

    如果有了拷贝构造函数和重载赋值运算符的函数,那么在初始化的时候自然而然调用的是拷贝构造函数;在赋值的时候自然而然地是调用重载赋值运算符的函数。

    不过或许我们还有疑问:如果只有两者的其中之一呢,比如说只有拷贝构造函数,那么赋值的情况又是什么;那如果是只有重载的赋值运算符函数而没有自定义的拷贝构造函数呢?那这初始化是什么情况?

    不管是哪一个问题,我们都要注意到系统地问题,如果问题是后者,那要注意的是系统为我们生成一个默认的拷贝构造函数,而前者的话我自己也不清楚,估计也是差不多吧~

    更多相关内容
  • 拷贝构造函数

    2021-05-22 12:21:16
    拷贝构造函数在C++中,与类名同名,且形参是本类对象的引用类型的函数,叫做拷贝构造函数(Copy Constrctor),与构造函数一样,当我们不主动定义的时候,系统也会自动生成一个,进行两个对象成员之间对应的简单赋值,...

    拷贝构造函数

    在C++中,与类名同名,且形参是本类对象的引用类型的函数,叫做拷贝构造函数(Copy Constrctor),与构造函数一样,当我们不主动定义的时候,系统也会自动生成一个,进行两个对象成员之间对应的简单赋值,用来初始化一个对象,如如下的情形:#include

    using namespace std;

    #define PI 3.1415

    class Circle

    {

    private:

    double R;

    public:

    Circle(double R);

    Circle(Circle &A);

    double area();

    double girth();

    };

    Circle::Circle(double R)

    {

    cout<

    this->R = R;

    }

    Circle::Circle(Circle &A)

    {

    cout<

    this->R = A.R;

    }

    double Circle::area()

    {

    return PI*R*R;

    }

    double Circle::girth()

    {

    return 2*PI*R;

    }

    int main()

    {

    Circle A(5);

    Circle B(A);

    return 0;

    }

    本例中定义了一个Circle圆形类,分别定义了带参数的构造函数和拷贝构造函数,然后在主函数中定义A对象,并传入初始值,调用带参数的构造函数。及定义B对象,通过A对象来初始化B对象。运行后可以看到

    27af697b3feb9760f1cfd1808ad99f49.png

    第一次定义的A对象调用带参数的构造函数,第二个B对象由于是通过A对象来初始化,所以调用拷贝构造函数。

    请大家也上机试验。

    大家可能疑问,在开头我们提到如果我们不主动定义拷贝构造函数,也会自动为我们生成一个,那我们为何还要自己定义呢?

    那是因为,默认的拷贝构造函数仅仅是做简单的赋值,有些情况则要出现问题,这就涉及到深拷贝与浅拷贝,我们在下一节给大家详细介绍!

    展开全文
  • 复制构造函数是构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用。复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的...

    复制构造函数是构造函数的一种,也称拷贝构造函数,它只有一个参数,参数类型是本类的引用。

    复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数,一个的参数是 const 引用,另一个的参数是非 const 引用,也是可以的。

    如果类的设计者不写复制构造函数,编译器就会自动生成复制构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。编译器自动生成的复制构造函数称为“默认复制构造函数”。

    注意,默认构造函数(即无参构造函数)不一定存在,但是复制构造函数总是会存在。

    下面是一个复制构造函数的例子。

    #include

    using namespace std;

    class Complex

    {

    public:

    double real, imag;

    Complex(double r, double i) {

    real= r; imag = i;

    }

    };

    int main(){

    Complex cl(1, 2);

    Complex c2 (cl); //用复制构造函数初始化c2

    cout<

    return 0;

    }

    第 13 行给出了初始化 c2 的参数,即 c1。只有编译器自动生成的那个默认复制构造函数的参数才能和 c1 匹配,因此,c2 就是以 c1 为参数,调用默认复制构造函数进行初始化的。初始化的结果是 c2 成为 c1 的复制品,即 c2 和 c1 每个成员变量的值都相等。

    如果编写了复制构造函数,则默认复制构造函数就不存在了。下面是一个非默认复制构造函数的例子。

    #include

    using namespace std;

    class Complex{

    public:

    double real, imag;

    Complex(double r,double i){

    real = r; imag = i;

    }

    Complex(const Complex & c){

    real = c.real; imag = c.imag;

    cout<

    }

    };

    int main(){

    Complex cl(1, 2);

    Complex c2 (cl); //调用复制构造函数

    cout<

    return 0;

    }

    程序的输出结果是:

    Copy Constructor called

    1,2

    第 9 行,复制构造函数的参数加不加 const 对本程序來说都一样。但加上 const 是更好的做法,这样复制构造函数才能接受常量对象作为参数,即才能以常量对象作为参数去初始化别的对象。

    第 17 行,就是以 c1 为参数调用第 9 行的那个复制构造函数初始化的。该复制构造函数执行的结果是使 c2 和 c1 相等,此外还输出Copy Constructor called。

    可以想象,如果将第 10 行删去或改成real = 2*c.real; imag = imag + 1;,那么 c2 的值就不会等于 c1 了。也就是说,自己编写的复制构造函数并不一定要做复制的工作(如果只做复制工作,那么使用编译器自动生成的默认复制构造函数就行了)。但从习惯上来讲,复制构造函数还是应该完成类似于复制的工作为好,在此基础上还可以根据需要做些別的操作。

    构造函数不能以本类的对象作为唯一参数,以免和复制构造函数相混淆。例如,不能写如下构造函数:

    Complex (Complex c) {...}

    复制构造函数被调用的三种情况

    复制构造函数在以下三种情况下会被调用。

    1) 当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用。例如,下面的两条语句都会引发复制构造函数的调用,用以初始化 c2。

    Complex c2(c1);

    Complex c2 = c1;

    这两条语句是等价的。

    注意,第二条语句是初始化语句,不是赋值语句。赋值语句的等号左边是一个早已有定义的变量,赋值语句不会引发复制构造函数的调用。例如:

    Complex c1, c2; c1 = c2 ;

    c1=c2;

    这条语句不会引发复制构造函数的调用,因为 c1 早已生成,已经初始化过了。

    2) 如果函数 F 的参数是类 A 的对象,那么当 F 被调用时,类 A 的复制构造函数将被调用。换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参。

    #include

    using namespace std;

    class A{

    public:

    A(){};

    A(A & a){

    cout<

    }

    };

    void Func(A a){ }

    int main(){

    A a;

    Func(a);

    return 0;

    }

    程序的输出结果为:

    Copy constructor called

    这是因为 Func 函数的形参 a 在初始化时调用了复制构造函数。

    前面说过,函数的形参的值等于函数调用时对应的实参,现在可以知道这不一定是正确的。如果形参是一个对象,那么形参的值是否等于实参,取决于该对象所属的类的复制构造函数是如何实现的。例如上面的例子,Func 函数的形参 a 的值在进入函数时是随机的,未必等于实参,因为复制构造函数没有做复制的工作。

    以对象作为函数的形参,在函数被调用时,生成的形参要用复制构造函数初始化,这会带来时间上的开销。如果用对象的引用而不是对象作为形参,就没有这个问题了。但是以引用作为形参有一定的风险,因为这种情况下如果形参的值发生改变,实参的值也会跟着改变。

    如果要确保实参的值不会改变,又希望避免复制构造函数带来的开销,解决办法就是将形参声明为对象的 const 引用。例如:

    void Function(const Complex & c)

    {

    ...

    }

    这样,Function 函数中出现任何有可能导致 c 的值被修改的语句,都会引发编译错误。

    思考题:在上面的 Function 函数中,除了赋值语句,还有什么语句有可能改变 c 的值?例如,是否允许通过 c 调用 Complex 的成员函数?

    3) 如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的复制构造函数被调用。换言之,作为函数返回值的对象是用复制构造函数初始化 的,而调用复制构造函数时的实参,就是 return 语句所返回的对象。例如下面的程序:

    #include

    using namespace std;

    class A {

    public:

    int v;

    A(int n) { v = n; };

    A(const A & a) {

    v = a.v;

    cout << "Copy constructor called" << endl;

    }

    };

    A Func() {

    A a(4);

    return a;

    }

    int main() {

    cout << Func().v << endl;

    return 0;

    }

    程序的输出结果是:

    Copy constructor called

    4

    第19行调用了 Func 函数,其返回值是一个对象,该对象就是用复制构造函数初始化的, 而且调用复制构造函数时,实参就是第 16 行 return 语句所返回的 a。复制构造函数在第 9 行确实完成了复制的工作,所以第 19 行 Func 函数的返回值和第 14 行的 a 相等。

    需要说明的是,有些编译器出于程序执行效率的考虑,编译的时候进行了优化,函数返回值对象就不用复制构造函数初始化了,这并不符合 C++ 的标准。上面的程序,用 Visual Studio 2010 编译后的输出结果如上所述,但是在 Dev C++ 4.9 中不会调用复制构造函数。把第 14 行的 a 变成全局变量,才会调用复制构造函数。对这一点,读者不必深究。

    展开全文
  • 拷贝构造函数,默认拷贝构造函数

    千次阅读 2019-09-20 18:05:52
    拷贝构造函数,默认拷贝构造函数 1.c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起 c++类的默认拷贝构造函数的弊端 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)...

    拷贝构造函数,默认拷贝构造函数
    1.c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起

    1. c++类的默认拷贝构造函数的弊端
      c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于:
      (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;
      (2)当类中没有定义拷贝构造函数时,编译器会默认提供一个拷贝构造函数,进行成员变量之间的拷贝。(这个拷贝操作是浅拷贝)
      class TestCls{
      public:
      int a;
      int *p;

    public:
    TestCls() //无参构造函数
    {
    std::cout<<“TestCls()”<<std::endl;
    p = new int;
    }

    ~TestCls()     //析构函数
    {
        delete p;   
        std::cout<<"~TestCls()"<<std::endl;
    }
    

    };
    int main(void)
    {
    TestCls t;
    return 0;
    }
    编译运行确实不会出错:

    类在我们没有定义拷贝构造函数的时候,会默认定义默认拷贝构造函数,也就是说可以直接用同类型的类间可以相互赋值、初始化:
    int main(void)
    { TestCls t1; TestCls t2 = t1; //效果等同于TestCls t2(t1); return 0; }
    这样结果就会出错。

    原因就在于,默认的拷贝构造函数实现的是浅拷贝。
    2.深度拷贝和浅拷贝
    深度拷贝和浅拷贝在c语言中就经常遇到的了,在这里我简单描述。
    一般的赋值操作是深度拷贝:

    //深度拷贝
    int a = 5;
    int b = a;
    简单的指针指向,则是浅拷贝:
    //浅拷贝
    int a = 8;
    int *p;
    p = &a;

    char* str1 = “HelloWorld”;
    char* str2 = str1;
    将上面的浅拷贝改为深度拷贝后:
    //深度拷贝
    int a = 8;
    int *p = new int;
    *p = a;

    char* str1 = “HelloWorld”;
    int len = strlen(str1);
    char *str2 = new char[len];
    memcpy(str2, str1, len);
    能看得出深度拷贝和浅拷贝的差异。拷贝者和被拷贝者若是同一个地址,则为浅拷贝,反之为深拷贝。 
    以字符串拷贝为例,浅拷贝后,str1和str2同指向0x123456,不管哪一个指针,对该空间内容的修改都会影响另一个指针。

    深拷贝后,str1和str2指向不同的内存空间,各自的空间的内容一样。因为空间不同,所以不管哪一个指针,对该空间内容的修改都不会影响另一个指针。

    1. 解决默认拷贝构造函数的弊端
      类的默认拷贝构造函数只会用被拷贝类的成员的值为拷贝类简单初始化,也就是说二者的p指针指向的内存空间是一致的。以前面TestCls可以知道,编译器为我们默认定义的拷贝构造函数为:
      TestCls(const TestCls& testCls)
      { a = testCls.a; p = testCls.p; //两个类的p指针指向的地址一致。 }
      main函数将要退出时,拷贝类t2的析构函数先得到执行,它把自身p指向的堆空间释放了;接下来,t1的析构函数得到调用,被拷贝类t1的析构函数得到调用,它同样要去析构自身的p指向指向的堆空间,但是该空间和t2类中p指向的空间一样,造成重复释放,程序运行崩溃。
      解决办法就是自定义拷贝构造函数;
      class TestCls{
      public:
      int a;
      int *p;

    public:
    TestCls()
    {
    std::cout<<“TestCls()”<<std::endl;
    p = new int;
    }

    TestCls(const TestCls& testCls)
    {
        cout<<"TestCls(const TestCls& testCls)"<endl;
        a = testCls.a;
        //p = testCls.p;
        p = new int;
        *p = *(testCls.p);      //为拷贝类的p指针分配空间,实现深度拷贝
    }
    
    ~TestCls()
    {
        delete p;   
      cout<<"~TestCls()"<<endl;
    }
    

    };

    int main(void)
    {
    TestCls t1;
    TestCls t2 = t1;
    return 0;
    }

    展开全文
  • 拷贝构造函数(复制构造函数)

    千次阅读 2019-03-17 15:44:34
    赋值构造函数 用一个对象初始化另一个对象 特别注意:初始化操作和 等号操作是两个不同的概念 1、初始化法 Class A { public: A(int a) { m_a = a; } A(int a,int b) { m_a = a; m_b = b; } A(const A...
  • 详解C++ 编写String 的构造函数、拷贝构造函数、析构函数和赋值函数编写类String 的构造函数、析构函数和赋值函数,已知类String 的原型为:class String{public:String(const char *str = NULL); // 普通构造函数...
  • 包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。
  • C++默认拷贝构造函数

    千次阅读 2019-07-24 17:13:42
    C++默认拷贝构造函数 转载来源 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空; (2)...
  • 函数参数为 对象的引用时,不会调用拷贝构造函数:class A {public:int *pa;public:A(int x){cout << "调用构造函数初始化成员变量" << endl;pa = new int;*pa = x;};//构造A(const A& obj){ //拷贝...
  • c++的默认拷贝构造函数,从深度拷贝和浅拷贝说起

    万次阅读 多人点赞 2017-07-24 19:44:10
    1. c++类的默认拷贝构造函数的弊端c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空;...
  • 类的拷贝构造函数

    千次阅读 2019-05-13 01:23:44
    为什么需要拷贝构造函数拷贝构造函数是一种特殊的构造函数,同样是初始化一个对象,不过其状态依赖于被拷贝对象。 什么是拷贝构造 如果一个构造函数的第一个参数是一个自身类类型的引用,且任何额外参数都有...
  • 前段时间学习C++,拷贝构造函数在三个时机会被调用,函数传参,新建对象,函数返回 函数返回时是怎么操作的呢,由于C语言没有this指针,所以我们借着C++的this指针可以打印出一些信息,顺便也可以猜测C语言的函数...
  • 什么是对象拷贝? 对象 对象 对象 数组A Object1 ...此时需要一个更大的数组来存放更多的内容,但是需要把原来的数据复制到新的更大的数组中。...如果是C语言,通常使用函数进行内存...
  • C++ 构造函数

    2021-05-22 04:12:27
    C++ 构造函数在本文中,您将学习C ++中的构造函数。您将学习什么是构造函数,如何创建它以及C ++中的构造函数类型。构造函数是成员函数的一种特殊类型,它在创建对象时会自动对其进行初始化。编译器通过其名称和返回...
  • 本文前面主要介绍了拷贝构造函数和赋值运算符函数的区别,以及在什么时候调用拷贝构造函数、什么情况下调用赋值运算符函数。最后,分析了下深拷贝和浅拷贝的问题,即拷贝构造函数和赋值运算符函数的必要性和意义。...
  • 构造函数在类中默认有一个无参的构造函数 默认的构造函数为 类名(){};这个构造函数 如果直接写了构造函数那么这个构造函数将会没有 构造函数 class MM { public: //MM() {};//无参构造函数 MM(int year,...
  • 文章目录函数的定义函数的的使用方法函数的返回值值传递指针传递引用传递C++引用作为函数返回值函数重载(Function Overloading)运算符重载(Operator Overloading)以成员函数的形式重载构造函数拷贝构造函数内联...
  • 拷贝构造函数 运算符重载 class Date { }; 可以看到,上面那个类没有任何成员,是一个空类,但是它真的什么都没有吗?其实一个类在我们不写的情况下,都会生成6个默认的成员函数 分别是构造函数,析构函数,拷贝...
  • 其实一个类在我们不写的情况下,也会生成6个默认的成员函数,分别是:构造函数,析构函数,拷贝构造函数,赋值运算符重载,取地址运算符重载,对const对象取地址运算符的重载 构造函数 构造函数是特殊的成员函数,...
  • #include <iostream> #include <string> using namespace std; class student { private: char *m_name; int m_age;... //构造函数(如果不写构造函数,系统会调用默认构造函数) stud...
  • C++深度解析 对象的构造(下)---无参构造函数,拷贝构造函数,深拷贝,浅拷贝(18)       特殊的构造函数 无参构造函数 当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空。 ...
  • 拷贝构造函数和拷贝赋值操作符拷贝构造函数 使用同类型对象来初始化自我对象(this) 格式Foo(const Foo& f); //只带一个参数,参数是同类型的const &何时调用拷贝构造函数 当使用拷贝构造时调用:Foo f1(f2); 使用...
  • 内联函数的引出-宏缺陷以及内联函数和编译器处理   宏的缺陷(effective c++里面我记得有讲) 1、在预处理时候在文件中进行展开,因此编译时期,编译器根本不知道宏变量的存在。 2、展开是无脑展开,很容易因为...
  • 什么是复制构造函数: 复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性 ,它的形参是本类的对象的引用,比如(类名 对象名)。它的作用是使用一个已经存在的对象(此对象由复制构造函数的参数决定...
  • 结构体、类、构造函数、拷贝构造函数 1、结构体 C C++ 区别: 1、定义变量时,stuct可以省略吗? 2、C++中的结构体 可以加函数原型 加了函数的好处:通过stu变量,不但可以得到stu.number、stu.name,还可以...
  • 在C++中复制控制是一个比较重要的话题,主要包括复制构造函数、重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果需要手动定义了其中了一个,那么另外的两个也需要定义,通常在存在指针或者前期相关操作...
  • 在说构造函数之前必须先说下C语言中类和对象 一、类的声明 有两种方式声明类,一种使用class来声明,一种使用struct来声明 class 【类名称】 { }; struct 【类名称】 { }; 这两者都可以用来声明一个对象,但是其...
  • 复制构造函数只有一个参数,由于在创建时传入的是同种类型的对象,所以一个很自然的想法是将该类型的对象作为参数,像这样: Sample (Sample a); 不幸的是,即使是这样朴实无华的声明也隐含了一个微妙的错误,呵,我们来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,042
精华内容 14,416
关键字:

拷贝构造函数c语言