赋值操作符、复制构造函数、析构函数、static成员练习
/**
* 定义一个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成员练习的更多相关文章
- C++反汇编第一讲,认识构造函数,析构函数,以及成员函数
C++反汇编第一讲,认识构造函数,析构函数,以及成员函数 以前说过在C系列下的汇编,怎么认识函数.那么现在是C++了,隐含有构造和析构函数 一丶认识构造函数 高级代码: class MyTest { ...
- C++,对象的 =赋值 以及 复制构造函数赋值
1. C++默认实现了 = 号赋值:operator=只要将一个对象的内容的内容逐位复制给另外一个对象即可. 2. C++默认实现了复制构造函数:同样,只要将一个对象的内容的内容逐位复制给另外一个对象 ...
- 赋值、复制构造函数和构造函数 & 异常安全的赋值
异常安全的赋值 需要注意,复制赋值和复制构造,相兼容. 赋值时候,要带上自检查.
- C++学习基础六——复制构造函数和赋值操作符
1.什么是复制构造函数 复制构造函数:是构造函数,其只有一个参数,参数类型是所属类的类型,且参数是一个const引用. 作用:将本类的成员变量赋值为引用形参的成员变量. 2.什么是赋值操作符 赋值操作 ...
- C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
一.本文目的与说明 1. 本文目的:理清在各种继承时,构造函数.复制构造函数.赋值操作符.析构函数的执行顺序和执行内容. 2. 说明:虽然复制构造函数属于构造函数的一种,有共同的地方,但是也具有一定的 ...
- c++ 复制构造函数和赋值函数
c++ 自动提供了下面这些成员函数 1默认构造函数 2.复制构造函数 3.赋值操作符 4.默认析构函数 5.地址操作符 赋值构造函数copy construtor 用于将一个对象复制到新创建的对象中, ...
- C++ 复制控制之复制构造函数
7月26日更新: 过了这么长的时间回过头来看,发现文章中有几个点说错(用红字标出): 构造函数不是只有唯一一个参数,它也可以是多参数形式,其第二参数及后继以一个默认值供应. 不是没有声明复制控制函数时 ...
- C++ 复制构造函数
C++类的设计中,如果某些函数没有显式定义,C++会自动生成,复制构造函数便是其中之一,其他的还有默认构造函数.赋值操作符.默认析构函数.地址操作符.一个类的复制构造函数的原型一般为: Class_n ...
- C++(二十七) — 深拷贝、浅拷贝、复制构造函数举例
1.复制构造函数.及new空间申请 复制构造函数,也是构造函数.只在初始化时调用,如果定义对象后赋值,比如,t1=t2,则只是运算符重载,没有调用构造函数. #include <iostream ...
随机推荐
- hdu 4460 第37届ACM/ICPC杭州赛区H题 STL+bfs
题意:一些小伙伴之间有朋友关系,比如a和b是朋友,b和c是朋友,a和c不是朋友,则a和c之间存在朋友链,且大小为2,给出一些关系,求出这些关系中最大的链是多少? 求最短路的最大距离 #include& ...
- hdu 4336 概率dp
题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率为p1,p2,````pN.每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 转移方程: ...
- [Java]进程与线程的区别(转)
线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)地址空间:进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间; (2)资源拥有: ...
- git 仓库迁移,git remote 更改源
git仓库迁移 我们有时候需要迁移git仓库,但又想保留每次commit的记录,所以我们只需要更改git remote [源]的问题即可 首先查看你的remote的地址 git remote -vv ...
- C#轻量级高性能日志组件EasyLogger
一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第六部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...
- AngularJS报错:[$injector:unpr] Unknown provider: $templateRequestProvider
在页面中由上到下引用了: angular.js angular-route.js 创建model的时候也写明了依赖: var someApp = angular.module('someApp',[' ...
- WCF X.509证书双向认证小结
最近在学习WCF X.509证书验证,想实现使用证书实现服务端和客户端的双向认证,实现原理是利用了数字证书包含的一对非对称密钥来实现数字签名及加密.所谓非对称密钥是采用两个密钥将加密和解密能力分开:一 ...
- iOS: 计算 UIWebView 的内容高度
- (void)webViewDidFinishLoad:(UIWebView *)wb { //方法1 CGFloat documentWidth = [[wb stringByEvaluating ...
- SpringMVC方法传递集合数组
背景:实体集合作为参数 数据准备: 1.实体类 class A {private int id; private String name; } 2.集合json字符串 [{"id&quo ...
- RDIFramework.NET V2.7 Web版本号升手风琴+树型文件夹(2级+)方法
级+)"界面风格,以展示多级功能菜单,满足用户的要求.Web展示效果例如以下: 要以"手风琴+树型文件夹(2级+)"的风格来展示功能模块,我们须要在"系统配置& ...