C++中构造函数详解

构造函数按参数为为:有参构造函数和无参构造函数

按类型分为:普通构造函数和拷贝构造函数

构造函数的三种调用方法:括号法,显示法,隐式转换法;

//括号法
Person p1;     //默认构造 无参构造
Person p2(13); //有参构造
Person p3(p2); //拷贝构造

//注意:使用无参构造时不要写括号。不然系统会认为该语句是函数声明。 例:Person p1();

//显示法
Person p1;
Person p2 = Person(13);//有参构造
Person p3 = Person(p2);//拷贝构造

//注意:右值的写法称为匿名对象,当前行执行完后,系统就会释放该对象。

//隐式转换法
Person p4 = 13;//相当于 Person p4 = Person(13);
Person p5 = p4;//拷贝构造

C++中拷贝构造函数的调用时机:

一,一般会使用一个已创建好的对象来初始化一个新对象

Person p1;

Person p2(p1);
Person p3 = Person(p2);
Person p4 = p3;

二,值传递方式给形参传值

void function(Person p)
{

}

int main()
{
    Person p1;
    function(p1);//这里以值传递,其实是Person temp = p1;调用拷贝构造函数

}

三,值返回方式返回局部对象

Person function()
{
    Person p1;//创建对象

    return p1;//返回局部对象
}

void test()
{
    Person p = function();//值传递实际上是用一个temp去拷贝原来的值,然后原来的局部对象被释放。temp作为返回值被接收。

}

构造函数调用规则。

如果自定义了有参构造函数,系统则不提供默认构造函数,但仍然提供拷贝构造函数。

如果自定义了拷贝构造函数,系统则不提供其他构造函数,需要的话要自己写。

深拷贝和浅拷贝

我们系统提供的默认拷贝构造函数是一种浅拷贝,所谓浅拷贝,其实就是简单的值拷贝,我们都知道,对象被释放的时候会调用析构函数,而析构函数的作用就是把对象的资源释放,例如你的对象有属性开辟到了堆区,析构时就需要delete释放掉。

class Person{
public:
    Person(string name,int age)
    {
        this->name = name;
        this->age = new int(age);//这个属性开辟到了堆区
    }

    Person(const Person &p)
    {
        name = p.name;
        age  = new int(*p.age);//深拷贝,new一块新的内存,避免重复释放同一内存
    }

    void show()
    {
        cout << name << endl;
        cout << *age  << endl;
    }

    ~Person()
    {
        if(age != NULL)
        {
            delete age;
            age = NULL;
        }

    }//

private:
    string name;
    int *age;

};

int main()
{
    Person p1("hzh",21);//初始化对象
    Person p2(p1);      //如果不写上面的拷贝构造函数,则默认拷贝构造(浅拷贝)
                        //这样会发送的问题,因为属性中有指针,浅拷贝时把指针指向的地址拷贝给了p2
                        //则两个指针指向的是同一个地址,而析构时会因为重复释放一块内存而造成错误。
   return 0;
}

要解决上述问题,就要自己写一个拷贝构造函数来实现深拷贝,具体操作为把开辟到堆区的属性在拷贝时重新new一块内存去存放。

到此这篇关于C++中构造函数详解的文章就介绍到这了,更多相关C++构造函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++拷贝构造函数中的陷阱

    转自微信公众号:CPP开发前沿 拷贝构造函数大家都比较熟悉,通俗讲就是传入一个对象,拷贝一份副本.不过看似简单的东西,实际不注意的话就会产生问题! #include<iostream> using namespace std; class CExample { public: int a,b,c; char *str; public: //构造函数     CExample(int tb)     {         a = tb;         b = tb+1;         c =

  • C++11 移动构造函数的使用

    目录 一.引言 二.左值和右值 三.深拷贝构造函数 四.右值引用 五.移动构造函数 六.std::move() 七.参考资料 一.引言 移动构造函数是什么?先举个例子,你有一本书,你不想看,但我很想看,那么我有哪些方法可以让我能看这本书?有两种做法,一种是你直接把书交给我,另一种是我去买一些稿纸来,然后照着你这本书一字一句抄到稿纸上. 显然,第二种方法很浪费时间,但这正是有些深拷贝构造函数的做法,而移动构造函数便能像第一种做法一样省时,第一种做法在 C++ 中叫做完美转发. 二.左值和右值 何为

  • c++特殊构造函数详解

    目录 前言 拷贝构造函数 一.什么是拷贝构造函数 二.调用时机 注意 浅拷贝和深拷贝 总结 前言 众所周知,构造函数的作用是类在创建对象时的初始化,而拷贝构造函数则是构造函数里的一种特殊构造. 拷贝构造函数 拷贝构造:是C++特有的,他是一种特殊的构造函数 用于基于一个同一个类的的第一个对象去创造和初始化的一个对象 第一的参数是本类的对象的引用(const) 一.什么是拷贝构造函数 一种特殊的构造函数,同一个类的一个对象去创造或初始化一个对象 在没写的时候,是默认存在的,自己写了之后,系统默认的

  • C++构造函数详解

    文章转自公众号:Coder梁(ID:Coder_LT) 上一篇文章我们介绍了定义了类,在使用之前,往往还需要对类进行初始化.这篇介绍的就是对类进行初始化的方法. 像是结构体,我们可以使用列表初始化的方法进行初始化: struct Thing {     char *pn;     int m; }; Thing th = {"hello", 23}; 但类不行,因为结构体当中的成员变量都是public的,而类往往是私有的.这意味着我们不能直接用程序访问数据成员,需要设计成函数. 在C+

  • C++构造函数一些常见的坑

    文章转自微信 公众号:Coder梁(ID:Coder_LT) 某一天我们接到了一个需求,需要开发一个类似于STL中string的类. 我们很快写好了代码: #include <iostream> #ifndef STRINGBAD_H_ #define STRINGBAD_H_ class StringBad {     private:      char *str;      int len;      static int num_strings;     public:      St

  • C++中构造函数详解

    构造函数按参数为为:有参构造函数和无参构造函数 按类型分为:普通构造函数和拷贝构造函数 构造函数的三种调用方法:括号法,显示法,隐式转换法: //括号法 Person p1; //默认构造 无参构造 Person p2(13); //有参构造 Person p3(p2); //拷贝构造 //注意:使用无参构造时不要写括号.不然系统会认为该语句是函数声明. 例:Person p1(); //显示法 Person p1; Person p2 = Person(13);//有参构造 Person p3

  • C++中的拷贝构造函数详解

    目录 C++拷贝构造函数(复制构造函数)详解 1) 为什么必须是当前类的引用呢? 2) 为什么是 const 引用呢? 默认拷贝构造函数 总结 C++拷贝构造函数(复制构造函数)详解 拷贝和复制是一个意思,对应的英文单词都是copy.对于计算机来说,拷贝是指用一份原有的.已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据.例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思. 在

  • javascript设计模式之对象工厂函数与构造函数详解

    下面通过文字详解加代码分析的方式给大家分享下javascript设计模式之对象工厂函数与构造函数的相关知识. 概述使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法.然而,除了这两种常用的对象创建方式,JavaScript还提供了其他方法创建对象.1).使用工厂函数创建对象我们可以编写一个函数,此函数的功能就是创建对象,可将其. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript还提

  • Java中LinkedList详解和使用示例_动力节点Java学院整理

    第1部分 LinkedList介绍 LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表.它也可以被当作堆栈.队列或双端队列进行操作. LinkedList 实现 List 接口,能对它进行队列操作. LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用. LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆. LinkedList 实现java.io.Serial

  • C/C++中多重继承详解及其作用介绍

    目录 概述 优缺点 优点 缺点 声明多重继承的方法 格式 例子 二义性 两个基类有同名成员 基类和派生类有同名成员 两个基类从同一个基类派生 概述 多重继承 (multiple inheritance): 一个派生类有两个或多个基类, 派生类从两个或多个基类中继承所需的属性. C++ 为了适应这种情况, 允许一个派生类同时继承多个基类. 这种行为称为多重继承. 优缺点 优点 自然地做到了对单继承的扩展 可以继承多个类的功能 缺点 结构复杂化 优先顺序模糊 功能冲突 声明多重继承的方法 格式 多重

  • C++赋值函数+移动赋值函数+移动构造函数详解

    目录 左值引用和右值引用 左值与右值 左右值的切换 左值引用:将左值绑定在引用上 常量左值引用和非常量左值引用 右值引用:将右值绑定在引用上 常量右值引用和非常量右值引用 移动构造函数 赋值和移动赋值函数 左值引用和右值引用 左值与右值 左值:在内存中占有确定位置的对象,即左值占有内存.换句话来说,就是有地址,有值. 右值:不占内存(科学地讲是临时寄存器),仅有值,为临时变量. 左右值的切换 右值->左值:用*符号. int a=10; int* b=&a;// b为右值. *b=20;//

  • Java中双向链表详解及实例

    Java中双向链表详解及实例 写在前面: 双向链表是一种对称结构,它克服了单链表上指针单向性的缺点,其中每一个节点即可向前引用,也可向后引用,这样可以更方便的插入.删除数据元素. 由于双向链表需要同时维护两个方向的指针,因此添加节点.删除节点时指针维护成本更大:但双向链表具有两个方向的指针,因此可以向两个方向搜索节点,因此双向链表在搜索节点.删除指定索引处节点时具有较好的性能. Java语言实现双向链表: package com.ietree.basic.datastructure.dublin

  • IOS 中UIApplication详解及实例

    IOS 中UIApplication详解及实例 以前刚学iPhone开发时,觉得UIApplication这个东西特NB,特神秘,比如它居然能打开一个URL,而且还是用一个很神秘的方法得到实例: [UIApplication sharedApplication] 它对我的神秘感一直保持到今天下午.今天下午负责UI设计的同事在设计,我没有素材,比较清闲,于是发个狠,专门看了一下UIApplication这个类.果然是难者不会,会者不难,看完之后,这个类的神秘感一下子没了.下面让我来揭开它的神秘面纱

  • IOS Object-C 中Runtime详解及实例代码

    IOS Object-C 中Runtime详解 最近了解了一下OC的Runtime,真的是OC中很强大的一个机制,看起来比较底层,但其实可以有很多活用的方式. 什么是Runtime 我们虽然是用Objective-C写的代码,其实在运行过程中都会被转化成C代码去执行.比如说OC的方法调用都会转成C函数 id objc_msgSend ( id self, SEL op, - ); 而OC中的对象其实在Runtime中都会用结构体来表示,这个结构体中包含了类名.成员变量列表.方法列表.协议列表.缓

随机推荐