zoukankan      html  css  js  c++  java
  • C++ Primer笔记9_构造函数_拷贝构造(深拷贝与浅拷贝)

    1.构造函数:


    >构造函数是一个特殊的、与类同名的成员函数,用于给每一个成员设置适当的初始值。

    1. >构造函数不能有返回值,函数名与类名同样。

    2. >缺省构造函数时,系统将自己主动调用该缺省构造函数初始化对象,缺省构造函数会将全部数据成员都初始化为零或       空。缺省构造函数是不带參数的构造函数。

    3. >创建一个对象时,系统自己主动调用构造函数。


    构造函数的特点:

         1.构造函数能够重载,传入什么实參决定调用不同版本号的构造函数。

         2.构造函数不能声明为const 、也不能声明为virtual;(析构函数能够)

         3.一个类假设自己定义了一个构造函数,编译器就不会生成默认构造函数。

         4.仅仅有构造函数才有类似初始化列表的形式来初始化成员变量(特别是const成员变量仅仅能在初始化列表中初始化)


    样例:

    #include <iostream>
    #include <new>
    
    class Person
    {
    public:
    	Person();//默认的构造函数
    	Person(int n, const string &str);//构造函数的重载
    private:
    	int age;
    	string *name;
    };
    
    


    2.拷贝构造


    先介绍一下深拷贝浅拷贝

    >浅拷贝: 指的是在对象复制时,仅仅对对象中的数据成员进行简单的赋值;默认拷贝构造函数运行的也是浅拷贝。        大多情况下“浅拷贝”已经能非常好地工作了,可是一旦对象存在了动态成员,那么浅拷贝就会出问题了。

    >深拷贝:当类的成员变量有指针类型时,拷贝对象时应该为指针变量又一次分配好空间,避免浅拷贝中仅仅拷贝指针的    值,使得两个指针指向同一块内存空间。


    浅拷贝缺陷样例:

    #include <iostream>
    #include <new>
    
    using namespace std;
    
    class Person
    {
    public:
    	Person();
    	Person(int n, const string &str);//构造函数重载
    	~Person();
    private:
    	int age;
    	string *name;
    };
    
    Person::Person():age(0), name(NULL)//构造函数初始化列表,定义时不必写!
    {
    	cout << "Default Person" << endl;
    }
    
    Person::Person(int n, const string &str):age(n), name(new string(str))
    {
    	cout << "Init Person" << endl;
    }
    
    Person::~Person()
    {
    	if(name)
    	{
    		cout << "~Person " << "name: " << *name << " age: " << age << endl;
    	}
    	delete name;
    }
    
    int main()
    {
    	Person p1(10, string("SCOTT"));
    	Person p2 = p1;
    
    	return 0;
    }
    

    执行结果:

    Init Person
    ~Person name: SCOTT age: 10
    Segmentation fault (core dumped)

    程序崩溃原因:

           p2由p1初始化而得到,因为我们没有自己定义拷贝构造函数,所以调用的是默认的拷贝构造函数,属于浅拷贝,仅仅对name的值进行了拷贝;p1与p2中的name指针指向同一个new空间,最后调用析构函数时,会造成两次delete而出现段错误。

    例如以下图所看到的:




    解决方法:自己定义拷贝构造函数! 达到深拷贝的效果

    深拷贝样例:

    #include <iostream>
    #include <new>
    
    using namespace std;
    
    class Person
    {
    public:
    	Person();
    	Person(int n, const string &str);
    	Person(const Person &n);
    	~Person();
    private:
    	int age;
    	string *name;
    };
    
    Person::Person():age(0), name(NULL)
    {
    	cout << "Default Person" << endl;
    }
    
    Person::Person(int n, const string &str):age(n), name(new string(str))
    {
    	cout << "Init Person" << endl;
    }
    //自己定义拷贝构造函数
    Person::Person(const Person &n)
    {
    	if(n.name)
    	{
    		name = new string(*n.name);
    		age = n.age;
    	}
    }
    
    Person::~Person()
    {
    	if(name)
    	{
    		cout << "~Person " << "name: " << *name << " age: " << age << endl;
    	}
    	delete name;
    }
    
    int main()
    {
    	Person p1(10, string("SCOTT"));
    	Person p2 = p1;
    
    	return 0;
    }

    执行结果:

    Init Person

    ~Person name: SCOTT age: 10

    ~Person name: SCOTT age: 10
    没有出现段错误,由此可见,上述解决方式可行。





  • 相关阅读:
    搭建负载均衡的环境(利用虚拟机上的四台centos)
    java的IO,AIO简单对比
    【每日分享】关于漏测
    安装xampp后,遇到的各种问题
    端口占用问题——netstat命令
    随笔
    AJAX 状态值(readyState)与状态码(status)详解
    CSS 实践:实现下拉菜单的方法
    css3动画总结
    判断手机运营商
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3835547.html
Copyright © 2011-2022 走看看