/**
* 定义一个Employee类,包含雇员名字和一个唯一的雇员标识,为该类定义默认构造函数和参数为表示
* 雇员名字的string构造函数。如果该类需要复制构造函数或赋值操作符,实现这些函数
*
* 注意:static数据成员必须在类定义体的外部定义(正好一次),static成员不是通过类构造函数进行初始化
* 而是应该在定义时进行初始化。
* (保证对象正好定义一次的最好方法就是将static数据成员的定义放在包含类的非内联成员函数定义的文件中)
* static数据成员通常在定义时才初始化(例外:只要初始化式是一个常量表达式)
* const static数据成员就可以在类的定义体中进行初始化,但是,const static数据成员在类定义体中初始化时,
* 该数据成员扔必须在类的定义体之外进行定义。
*/
class Employee
{
public:
//构造函数
Employee():name("Noname"), id(counter)
{
++counter;
}
Employee(const std::string &nm):name(nm), id(counter)
{
++counter;
}
//复制构造函数
Employee(const Employee &other):name(other.name), id(counter)
{
++counter;
}
//赋值操作符
Employee& operator = (const Employee &other)
{
name = other.name;
return *this;
} private:
std::string name;
int id;
static int counter;
};
int Employee::counter = ;//另外需要在类外对static成员进行定义和初始化:

 复制构造函数可用于:

1、根据另一个同类型的对象显示或隐式初始化一个对象;

2、复制一个对象,将它作为实参传给一个函数;

3、从函数返回时复制一个对象;

4、初始化顺序容器中的元素;

例如:

 /*
可以用表示容量的单个形参初始化容器,这种方式使用了默认构造函数和复制构造函数
*/
vector<string> svec();
/*
编译器首先使用string函数的默认构造函数创建一个临时值来初始化svec,然后使用复制构造函数将临时值复制到svec的每个元素中。
*/

5、根据元素初始化式列表初始化数组元素。

例如:

 /*
如果没有为类类型的数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用了常规的花括号括住的数组初始化列表来提供显示元素初始化式,则使用复制初始化来初始化每个元素。根据指定值创建适当类型元素,然后用复制构造函数将该值复制到相应元素:
*/
sales_item primer_eds[] = { string("0-201-15487-6").
string("0-201-14387-8").
string("0-201-23487-3").
Sales_item()
} ;
/*
前三个元素的初始化式中可以直接指定一个值,用于调用元素类型的单实参构造函数(前提是该构造函数不能为 explicit 类型的),如果不希望指定实参或指定多个实参,就需要使用完整的构造函数语法,如最后一个元素的初始化那样。
*/

对于类类型对象:

直接初始化:直接调用与实参匹配的构造函数

复制初始化:总是调用复制构造函数,首先使用指定的构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象

一般而言,如果一个类拥有指针成员,或者在复制对象时有一些特殊工作要做,则该类需要复制构造函数

一般而言,如果一个类需要定义复制构造函数,则该类也需要定义赋值操作符

复制构造函数的形参并不限制为const,但必须是一个引用,解释这个限制的基本原理,例如,解释为什么下面的定义不能工作,

       Sales_item::Sales_item( const Sales_item rhs );

它不能工作的原因是:当形参为非引用类型时,将复制实参的值,给这个copy constructor,但是,每当以传值方式传递参数时,会导致调用复制构造函数,因此,如果要使用以传值方式传递参数的copy constructor,必须使用一个“不以传值方式传递参数”的copy constructor,否则就会导致copy constructor的无穷递归调用。这个“不以传值方式传递参数”的方法就是使用 形参是一个引用 的copy constructor,即以传地址的方式传递参数。

什么是析构函数?合成析构函数有什么用?什么时候会合成析构函数?什么时候一个类必须定义自己的析构函数?

析构函数是一个成员函数,它的名字与类的名字相同,在名字前加一个代字符~,没有返回值,没有形参(因此析构函数不能重载),用于类的对象超出作用域时释放对象所获取的资源,或删除指向动态分配对象的指针。

合成析构函数的作用:1,按对象创建时的逆序撤销每个非static成员,2,对于类类型的成员,合成析构函数调用该成员的析构函数来撤销对象。

编译器总会为每个类合成一个析构函数。当1,需要释放指针成员的资源时,2,需要执行某些特定工作时,必须自己定义析构函数。

析构函数与复制构造函数或赋值操作符之间的一个重要区别是,即使我们编写了自己的析构函数,合成析构函数仍然运行

 class Exmp1
{
public:
//默认构造函数
Exmp1()
{
std::cout << "Exmpl()" << std::endl;
}
//复制构造函数
Exmpl(const Exmpl&)
{
std::cout << "Exmpl(const Exmpl &)" << std::endl;
}
//赋值操作符
Exmpl& operator = (const Exmpl &rhe)
{
std::cout << "Exmpl& operator = (const Exmpl &) << std::endl";
reurn *this;
}
//析构函数
~Exmpl()
{
std::cout << "~Exmpl()" << std::endl;
}
};
void fun1(Exmpl obj) //形参为Exmpl对象
{
}
void fun2(Exmpl& obj) //形参为Exmpl对象引用
{
}
Exmpl fun3()
{
Exmpl obj;
return obj; // 返回Exmpl对象
} int main()
{
Exmpl eobj; //调用默认构造函数创建Exmpl对象eobj fun1(eobj); //调用复制构造函数--将形参Exmpl对象创建为实参Exmpl对象副本---函数执行完毕后调用析构函数撤销形参Exmpl对象 fun2(eobj); //形参为引用,无需调用复制构造函数传递实参 eobj = fun3();
/*调用默认构造函数创建局部Exmpl对象---函数返回时调用复制构造函数创建作为返回值副本的Exmpl对象
---调用析构函数撤销局部Exmpl---调用赋值操作符---调用析构函数撤销作为返回值副本的Exmpl对象 */ Exmpl *p = new Exmpl; // 调用默认构造函数动态创建Exmpl对象 std::vector<Exmpl> evec();
/*调用默认构造函数创建一个临时值Exmpl对象---然后三次调用复制构造函数将临时值Exmpl对象复制到vector容器
evec的每个元素---调用析构函数撤销临时值Exmpl对象*/ delete p; //调用析构函数撤销动态创建的Exmpl对象 return ; // evec及eobj生命周期结束,自动调用析构函数撤销---撤销evec需调用析构函数三次(因为其有三个元素,按照逆序撤销)
}

复制控制练习:

 1 class TreeNode
2 {
3 public:
4 TreeNode():count(0), left(0), right(0){}
5 TreeNode(const TreeNode&);
6 ~TreeNode();
7 private:
8 std::string value;
9 int count;
10 TreeNode *left;
11 TreeNode *right;
12 };
13
14 TreeNode::TreeNode(const TreeNode &orgi):value(orgi.value), count(orgi.count)
15 {
16 if(orgi.left)
17 left = new TreeNode(*orgi.left);
18 else
19 left = 0;
20 if(orgi.right)
21 right = new TreeNode(*orgi.right);
22 else
23 right = 0;
24 }
25 TreeNode::~TreeNode()
26 {
27 if(left)
28 delete left;
29 if(right)
30 delete right;
31 }

赋值操作符、复制构造函数、析构函数、static成员练习的更多相关文章

  1. C++反汇编第一讲,认识构造函数,析构函数,以及成员函数

    C++反汇编第一讲,认识构造函数,析构函数,以及成员函数 以前说过在C系列下的汇编,怎么认识函数.那么现在是C++了,隐含有构造和析构函数 一丶认识构造函数 高级代码: class MyTest { ...

  2. C++,对象的 =赋值 以及 复制构造函数赋值

    1. C++默认实现了 = 号赋值:operator=只要将一个对象的内容的内容逐位复制给另外一个对象即可. 2. C++默认实现了复制构造函数:同样,只要将一个对象的内容的内容逐位复制给另外一个对象 ...

  3. 赋值、复制构造函数和构造函数 & 异常安全的赋值

    异常安全的赋值 需要注意,复制赋值和复制构造,相兼容. 赋值时候,要带上自检查.

  4. C++学习基础六——复制构造函数和赋值操作符

    1.什么是复制构造函数 复制构造函数:是构造函数,其只有一个参数,参数类型是所属类的类型,且参数是一个const引用. 作用:将本类的成员变量赋值为引用形参的成员变量. 2.什么是赋值操作符 赋值操作 ...

  5. C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容

    一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...

  6. c++ 复制构造函数和赋值函数

    c++ 自动提供了下面这些成员函数 1默认构造函数 2.复制构造函数 3.赋值操作符 4.默认析构函数 5.地址操作符 赋值构造函数copy construtor 用于将一个对象复制到新创建的对象中, ...

  7. C++ 复制控制之复制构造函数

    7月26日更新: 过了这么长的时间回过头来看,发现文章中有几个点说错(用红字标出): 构造函数不是只有唯一一个参数,它也可以是多参数形式,其第二参数及后继以一个默认值供应. 不是没有声明复制控制函数时 ...

  8. C++ 复制构造函数

    C++类的设计中,如果某些函数没有显式定义,C++会自动生成,复制构造函数便是其中之一,其他的还有默认构造函数.赋值操作符.默认析构函数.地址操作符.一个类的复制构造函数的原型一般为: Class_n ...

  9. C++(二十七) — 深拷贝、浅拷贝、复制构造函数举例

    1.复制构造函数.及new空间申请 复制构造函数,也是构造函数.只在初始化时调用,如果定义对象后赋值,比如,t1=t2,则只是运算符重载,没有调用构造函数. #include <iostream ...

随机推荐

  1. BZOJ 3101: N皇后 构造

    3101: N皇后 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=3101 Description n*n的棋盘,在上面摆下n个皇后,使其 ...

  2. spring cloud 学习(5) - config server

    分布式环境下的统一配置框架,已经有不少了,比如百度的disconf,阿里的diamand.今天来看下spring cloud对应的解决方案: 如上图,从架构上就可以看出与disconf之类的有很大不同 ...

  3. bash编程之xargs实用技巧

    xargs结合管道操作符|,可以完成很多看似复杂的问题: 1.快速删除所有.log日志文件 机器运行久了,就会有各式各样的日志文件,散落在各个目录下,可以利用下面的方法: find ./ -name ...

  4. 关于 C 语言,我喜欢和讨厌的十件事

    前言:最近有个家伙抱怨道“为什么我还要再用C?”-虽然我不同意他的说法,但至少他随口提到如果你“在一台拇指大小的电脑”上编程,或者为一门语言写引导程序,那么可以用C语言.要我说,写设备驱动,或者特定平 ...

  5. .Net 环境下C# 通过托管C++调用本地C++ Dll文件

     综述 : 本文章介绍.Net 环境下C# 通过托管C++调用本地C++ Dll文件, 示例环境为:VS2010, .Net4.0, Win7. 具体事例为测试C++, C#, 及C#调用本地C++D ...

  6. mysql 阿里内核人员

    丁奇 http://dinglin.javaeye.com/ 鸣嵩 @曹伟-鸣嵩 (新浪微博) 彭立勋 http://www.penglixun.com/ 皓庭 http://wqtn22.iteye ...

  7. 查看内核页表kernel_page_tables (aarch32)

    作者 彭东林 pengdonglin137@163.com   平台 Linux-4.10.17 Qemu + vexpress-ca9     概述 通过配置内核,会在/sys/kernel/deb ...

  8. 在ASP.NET MVC中使用Knockout实践08,使用foreach绑定集合

    本篇体验使用 foreach 绑定一个Product集合. 首先使用构造创建一个View Model. var Product = function(data) { this.name = ko.ob ...

  9. Android:Attribute is missing the Android namespace prefix

    今天编写XML文件时,出现了Attribute is missing the Android namespace prefix的错误,开始一直找没找出原因,后来仔细一看原来只是一个很简单的单词书写错误 ...

  10. C#输出到Release VS中Release模式下生成去掉生成pdb文件

    Release 与 Debug 的区别就不多说了, 简单来说 Release 优化过, 性能高一些. Debug 为方便调试. 默认情况下是 Debug, 那如何改成 Release 呢? 项目上右键 ...