对象的初始化、拷贝构造和析构函数 20131002

构造函数、析构函数、赋值函数是类的基本函数。每一个类只有一个析构函数,但是可以有多个构造函数、多个赋值函数。一般如果类中没有显示的声明和定义上述函数,C++编译器会自动为其生成4个public inline默认函数A(), A(const A&), ~A(), A& operator=(constA& a)

1.构造函数和析构函数的起源

C++编译器有更加严格的类型安全检查机制,几乎可以找到程序的所有语法错误。但是很多错误因为变量没有争取的初始化或者清除导致,而初始化和清除的工作经常被遗忘,所以有了类的构造函数用于初始化数据成员,当创建对象的时候,构造函数自动被调用执行;当对象消亡的时候,析构函数被自动调用。因此不要在构造函数中做那些和初始化对象无关的工作,也不要在析构函数中做哪些和销毁对象无关的工作。

2.为为什么需要构造函数和析构函数

编译期间无法确定一个程序运行期间会创建什么类型的对象,对象的初始化工作最好是通过一个函数执行,而且是在对象创建的同时,这就是构造函数,同样对象销毁的时候,需要一个函数销毁对象的资源,就是析构函数。

创建一个变量和动态对象的时候,一定不要忘记初始化,否则会直接访问原始的内存,出现错误。初始化工作是在对象创建的同时使用初始值直接填充对象的内存单元,银子中间不会有数据类型转化的中间过程,也不会产生临时对象;但是赋值操作是在对象创建好的时候,进行的赋值操作,过程可能需要类型转换,也就是会产生临时变量。

构造函数一个用途还有给一些可能存在的隐含成员创建一个初始化的机会如vptr,否则虚拟机制将无法实现。

3.构造函数的成员初始化列表

一般我们会在构造函数中初始化成员数据成员,这不是真正意义上的初始化,而是赋值。真正的初始化是使用的所谓的“初始化表达式表”进行的,初始化列表是在构造参数表之后,在函数体{}之前。这说明该列表的初始化工作发生在函数体内的任何代码被指向前,而且编译器也是这样做的。

构造函数的初始化列表使用规则:

1)如果类之间存在继承关系,派生类可以直接在初始化列表中调用基类中的特定构造函数向他传递参数,因为我们不能在初始化对象的时候访问基类的数据成员。

class A{public: A(int x);};

class B: public A{B(int x, int y);};

B::B(int x,int y): A(x){….}

2)类的非静态const数据成员和引用成员只能够在初始化列表中初始化,因为他们只存在初始化语义,而不存在赋值语义。

3)类的数据成员的初始化可以采用初始化列表或函数体内赋值的两种方法,但是两者效率不完全相同。当传递的是一个类型的参数进行初始化的时候,建议使用初始化列表:

B::B(const A & a): m_a(a){….}

B::B(const A & a){m_a= a}

对于第一种方式,类B的构造函数在初始化类表中调用了类A的拷贝构造函数进行初始化;但是对于第二种方式,手下先创建一个m_a对象(调用A的默认构造函数),在调用A的复制函数,在将参数a赋值给m_a。

4.对象的构造和析构次序

这里的构造和析构次序不是给对象分配的内存空间的次序,而是说对象的初始化和销毁的次序。如果一个类中没有基类,他的构造过程十分简单。但是对于派生类,他的构造函数将首先调用它的基类的构造函数,因此任何一个对象都是首先构造最根类的子对象。

析构函数会严格按照和对象构造的相反次序指向,器而是唯一的。数据成员的初始化次序完全不受他们在初始化列表中的出现次序的影响,只由他们在类中声明的次序决定

5.构造函数和析构函数的调用时机

非静态的局部对象: 程序执行贷该对象的定义的时候,创建对象并且调用相应的构造函数,如果没有提供初始值,则调用默认的构造函数;程序执行到对象的生存域的时候暗中调用对象的析构函数。

静态的局部对象:如果没有默认的构造函数,自动初始化为0,直到程序结束的时候才会调用析构函数。

全局对象:在程序进入main 之前自动调用他们对应的构造函数进行初始化,但是初始化的顺序不确定;如果没哟默认的构造函数则会初始化为0,直到main函数结束之后才会调用析构函数。

类的静态数据成员对象:等同于全局对象的情况

对象的引用:初始化和销毁都不会调用构造函数和析构函数,也正是因为如此,引用传递参数比传递只高效;

动态对象的创建:在new的时候调用构造函数,在delete的时候调用析构函数

对象的赋值:调用类型匹配的operator=重载函数。

6.构造函数和赋值函数的重载

C++中允许实现多个构造函数,即构造函数的重载,可以实现不同的方式初始化对象。不能够同时定义一个无参数的默认构造函数和一个参数全部都会有默认值的构造函数,这样会出现二义性的问题。

拷贝构造函数式这样的构造函数:第一个参数是该类型对象的引用,const引用, volatile引用和const volatile引用,并且不存在其他的采纳数或者其他的参数都有默认值。 拷贝构造函数的参数必须是同类对象的引用,而不是对象值。

类的赋值函数也是一种拷贝函数,当然也可以实现重载:

A& operator=(const A& a);

A& operator=(A & copy);

A& operator=(A copy);

最后一种方式会调用当前类的构造函数。

7.String类的构造函数和析构函数

C++中的初始化的值是‘/0’,而不是NULL,因此在任何的C++string中大小至少为1;空字符串也是有效的字符串,长度是1

8.拷贝构造函数和赋值函数,在需要深复制的时候,需要重写这些函数,如string 指针等等。

9String类型的赋值函数

String & String::operator=(const String & other){

If(this != other){

Char * temp = new char[strlen(other)+1];

strcpy(temp,other);

delete []m_data;

m_data= other;

}

}

10阻止编译器自动生成,我们需要手动实现这两个函数,同时将函数体内部置空即可,同时可以设置访问权限是private。

11.基类的构造函数、析构函数赋值函数都是不能够被子类继承的,如果类之间存在继承关系需要注意:

派生类的构造函数应该在初始化的列表中中显示的调用基类的构造函数(除非基类的构造函数可以不访问);

如果基类是多态类,必须把基类的析构函数声明在虚函数,这样就可实现动态的绑定,否则会造成内存泄露。

class Base{

public:

Base(){

cout << "Base::Base()" << endl;

}

virtual ~Base(){

cout << "Base::~Base()" << endl;

}

};

class Derived:public Base{

public:

Derived(){

cout << "Derived::Derived()" << endl;

}

virtual ~Derived(){

delete p_base;

cout << "Derived::~Derived()" << endl;

}

private:

Base *p_base;

};

int main()

{

Base * b = new Derived;

delete b;

return 0;

}

追梦的飞飞

于广州中山大学20131002

C++复习10.对象的初始化拷贝析构函数的更多相关文章

  1. 10.C++-构造函数初始化列表、类const成员、对象构造顺序、析构函数

    首先回忆下,以前学的const 单独使用const修饰变量时,是定义的常量,比如:const int i=1; 使用volatile const修饰变量时,定义的是只读变量 使用const & ...

  2. C++ //拷贝构造函数调用时机//1.使用一个已经创建完毕的对象来初始化一个新对象 //2.值传递的方式给函数参数传值 //3.值方式返回局部对象

    1 //拷贝构造函数调用时机 2 3 4 #include <iostream> 5 using namespace std; 6 7 //1.使用一个已经创建完毕的对象来初始化一个新对象 ...

  3. c++——对象的构造和析构函数、构造函数的分类及调用

    1构造函数和析构函数的概念 有关构造函数 1构造函数定义及调用 1)C++中的类可以定义与类名相同的特殊成员函数,这种与类名相同的成员函数叫做构造函数: 2)构造函数在定义时可以有参数: 3)没有任何 ...

  4. C++学习(9)—— 对象的初始化及清理

    1. 构造函数和析构函数 对象的初始化和清理是两个非常重要的安全问题 ​ 一个对象或者变量没有初始状态,对其使用后果是未知 ​ 同样的使用完一个对象或者变量,没有及时清理,也会造成一些安全问题   C ...

  5. JAVA中JavaBean对象之间属性拷贝的方法

    JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...

  6. C++核心编程 4 类和对象-对象的初始化和清理

    构造函数和析构函数 对象的初始化和清理工作是两个非常重要的安全问题,一个对象或者变量没有初始状态,对其使用结果是未知的,同样,使用完一个对象或变量,没有及时清理,也会造成一定的安全问题.C++利用了构 ...

  7. Java复习10.Servlet编程

    Java复习10. Servlet编程知识 20131008 前言: 之前在大三下的时候,学习了一个月的JSP和Servlet知识,但是没有什么项目经验,把JSP Web开发学习实录看了前面几张,后面 ...

  8. C++ 对象的初始化

    目录 默认初始化 默认构造函数(default constructor) 构造函数初始值列表(cosntructor initializer list) 直接初始化和拷贝初始化 拷贝构造函数(copy ...

  9. 解析Java类和对象的初始化过程

    类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...

随机推荐

  1. C++ char float int string 之间的转换

    string str = "123"; string 转 int int i = atoi( str.c_str() ); string 转 float float f = ato ...

  2. require-ensure

    require-ensure 说明: require.ensure在需要的时候才下载依赖的模块,当参数指定的模块都下载下来了(下载下来的模块还没执行),便执行参数指定的回调函数.require.ens ...

  3. PreparedStatement和Statement区别详解

    技术原理 该 PreparedStatement接口继承Statement,并与之在两方面有所不同: PreparedStatement 实例包含已编译的 SQL 语句.这就是使语句“准备好”.包含于 ...

  4. 激活webstorm(作为一个伪前端,偶尔用用)

    推荐博客:https://blog.csdn.net/voke_/article/details/76418116 我试的方法一.

  5. LeetCode (226):Invert Binary Tree 递归实现

    Invert a binary tree. 4 / \ 2 7 / \ / \ 1 3 6 9 to 4 / \ 7 2 / \ / \ 9 6 3 1 Trivia:This problem was ...

  6. java计算两个日期之间相隔的月份(向下取整)

    最近需求里面有个需要计算两个日期之间相隔的月份,写起来还挺繁琐,需要将各种情况都要考虑到,写了一个作为以后自己的工具吧. //获取哪一天 public static int getDay(Date d ...

  7. Graph_Master(连通分量_D_Trajan缩点+dfs)

    hdu_2242 题目大意:求将一张无向图(n个点,m条边)移除一条边分为不连通两部分,使得两部分的点权和最接近,若无法分为两部分,则输出impossible. 题解:拿到题面还算清晰,就是先tarj ...

  8. docker shipyard 问题

    安装 docker  shipyard curl -s https://shipyard-project.com/deploy | bash -s docker machine 创建的虚拟机无法直接运 ...

  9. spring boot2.1读取 apollo 配置中心1

    第一篇:搭建apollo配置中心 为什么选择apollo,我做了一些对比:   Diamond Disconf Apollo Spring Cloud Config 数据持久性 mysql mysql ...

  10. JavaScript高级程序设计-读书笔记(7)

    第22章 高级技巧 1.高级函数 (1)安全的类型检测 在任何值上调用Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串. ...