1:当函数以相应的类作为形参列表时,对象可以作为函数的参数传入。在学习函数时,我们曾提过,值传递先复制实参产生副本。那么对象的副本是怎样的呢?

复制构造函数是指类的对象被复制时所调用的函数。下面两种情况中对象都会调用复制构造函数。

(1)将一个对象赋值给另外一个对象时。例如:

对象1=对象2;

对象1(对象2);

上面的程序中对象2的复制构造函数会被调用。

(2)作为值传递的实参。例如:

function(对象1);

在function函数体内,使用的是对象1的副本。所以之前会调用对象1的复制构造函数。

和构造函数一样,C++在未发现自定义的复制构造函数之前会创建一个默认的构造函数。

自定义的复制构造函数的声明格式为:

类名(类名& 形参)

值得注意的是,复制构造函数时引用传递的函数。既然默认复制构造函数已经完成复制工作,那为何需要重新定义它呢?例如,一个类具有指针类型的数据,默认复制构造函数执行之后,原对象和副本的指针成员指向的是同一个内存空间。通过指针改变该内存,就会改变两个对象实际应用的数据(也就是这块内存的内容)。这时可以自定义复制构造函数,将两个指针的内存分离开。

2:代码如下:

(1)germ.h

#include <string>
using std::string;
class germ{
public:
int m_age;
string m_name;
germ(germ& g);//自定义复制构造函数 类名(类名&形参)
germ(string s);//构造函数
~germ();//析构函数,执行收尾工作
};

(2)germ.cpp

#include "stdafx.h"
#include "germ.h"
#include <iostream>
using std::cout;
using std::endl;
germ::germ(string s)
{
m_name = s;
m_age = ;
cout<<"发现了"<<m_name<<endl;
}
germ::germ(germ& g)
{
g.m_age +=;
this->m_age = ;
this->m_name =g.m_name + "的复制体";
cout<<"产生了"<<g.m_name<<"的复制体"<<endl;
}
germ::~germ(){
cout<<this->m_name<<"被消灭了"<<endl;
}

(3)main.cpp

// 7.7.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include "germ.h"
using std::cout;
using std::endl;
germ copyGerm(germ gc)
{
return gc;
}
int main()
{
germ g1("有氧菌");//(发现了有氧菌)
germ g2(g1);//第一个germ的意思是声明一个对象g2,g2(g1)的意思是将g1赋值给g2,此时将会调用复制构造函数(产生了有氧菌的复制体)
germ g3("无氧菌");//(发现了无氧菌)
germ g4 = g3;//意思同样是将g3赋值给g4,此时将会调用复制构造函数。(产生了无氧菌的复制体)
germ g5 = copyGerm(g4);//此时也调用复制构造函数了,只要有副本,就会调用复制构造函数。此处调用了两次,copygerm()一次,等号一次(产生了无氧菌复制体的复制体,产生了无氧菌复制体的复制体的复制体)
return ;
}
//注意,调用copygerm后,copygerm会立即被释放,所以会立即放出析构函数,输出(无氧菌的复制体的复制体被消灭了)
//以后依次g5,g4,g3,g2,g1被释放,故依次被输出这些被消灭

运行结果:

从程序运行结果来分析代码:首先在主函数中产生了g1对象,由复制构造函数产生了g1的复制体g2——有氧菌复制体。之后定义了g3——无氧菌。通过复制构造函数产生了g3的复制体g4。前四行输出即是上面所述的过程。g5的产生前,g5所在赋值语句等号右边的copyGerm函数被调用,传递的实参为g4——无氧菌的复制体。如同开始提到的,值传递实参对象产生副本,副本就是形参gc——无氧菌复制品的复制品。函数执行完毕后,传递回临时变量,内容是gc。g5的值经过复制语句,所以它是gc(临时变量使用的内存)的复制品。

C++入门经典-例7.7-对象与复制,菌类的繁殖的更多相关文章

  1. C++入门经典-例7.8-const对象,标准尺寸

    1:当建立一个对象之后,如果不希望它的任何数据发生改变,可以将其直接声明为const对象,例如: const 类名 对象名 const对象必须初始化.我们可以调用它的数据和函数,但是不可以对他们进行修 ...

  2. C++入门经典-例6.6-字符串复制

    1:字符串复制函数strcpy的格式如下: strcpy(字符数组名,字符串) 其作用是把字符串中的字符串复制到字符数组中.需要注意的是,字符串结束标志'\0'也一同被复制. 注意是将后面的内容复制给 ...

  3. 《挑战30天C++入门极限》C++类对象的复制-拷贝构造函数

        C++类对象的复制-拷贝构造函数 在学习这一章内容前我们已经学习过了类的构造函数和析构函数的相关知识,对于普通类型的对象来说,他们之间的复制是很简单的,例如: int a = 10; int ...

  4. C++入门经典-例7.6-this指针,同一个类的不同对象数据

    1:对于类的非静态成员,每个对象都有自己的一份拷贝,即每个对象都有自己的数据成员,不过成员函数却是每个对象共享的.那么调用共享的成员函数如何找到自己的数据成员呢?答案是通过类中隐藏的this指针. 2 ...

  5. C++入门经典-例7.10-运算符的重载,重载加号运算符

    1:曾经介绍过string类型的数据,它是C++标准模版库提供的一个类.string类支持使用加号“+”连接两个string对象.但是使用两个string对象相减确实非法的,其中的原理就是C++所提供 ...

  6. C++入门经典-例9.3-类模板,简单类模板

    1:使用template关键字不但可以定义函数模板,而且可以定义类模板.类模板代表一族类,它是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的参数或返回值可以取任意数据类型.类 ...

  7. C++入门经典-例8.10-实现抽象类中的成员函数

    1:抽象类通常作为其他类的父类,如果从抽象类派生的子类是抽象类,则子类必须实现父类中的所有纯虚函数.代码如下: // 8.10.cpp : 定义控制台应用程序的入口点. // #include &qu ...

  8. C++入门经典-例8.9-抽象类,纯虚函数,创建纯虚函数

    1:包含有纯虚函数的类称为抽象类,一个抽象类至少具有一个纯虚函数.抽象类只能作为基类派生出的新的子类,而不能在程序中被实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针.在程序开发过程中并 ...

  9. C++入门经典-例8.8-虚继承

    1:以前讲到从CBird类和CFish类派生子类CWaterBird时,在CWaterBird类中将存在两个CAnimal类的复制.那么如何在派生CWaterBird类时使其只存在一个CAnimal基 ...

随机推荐

  1. JavaScript例子1-给网页中所有<p>元素添加onclick事件

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  2. wpf menuitem 简约显示的 template样式

    <ControlTemplate x:Key="MenuItemControlTemplate1" TargetType="{x:Type MenuItem}&qu ...

  3. linux系统编程相关

    基本的概念:程序,进程,并发,单道程序设计,多道程序设计,时钟中断. 存储介质:寄存器(操作系统的位数是针对寄存器而言的,32位识字节,64位就是8字节).缓存cache.内存,硬盘,网络. cpu的 ...

  4. 简单聊聊服务发现(redis, zk,etcd, consul)(转载)

    服务发现并没有怎样的高深莫测,它的原理再简单不过.只是市面上太多文章将服务发现的难度妖魔化,读者被绕的云里雾里,顿觉自己智商低下不敢高攀. 服务提供者是什么,简单点说就是一个HTTP服务器,提供了AP ...

  5. Jupyter Notebook不能自动打开浏览器

    安装了 Winpython,运行Jupyter Notebook.exe或Jupyter lab.exe,总是不能自动打开浏览器,提示"no web browser found" ...

  6. web端文件上传,预览,下载,删除

      //HTML部分 <div class="item attachment attachmentNew"> <span class="name&quo ...

  7. 关于SYSLINUX的一些重要描述摘录

    以下资源都来自官方文档,原文摘录 The SYSLINUX suite contains the following boot loaders ("derivatives"), f ...

  8. IO[File_API学习]

    IO流[File_API学习的使用] File_API学习的使用1.名称分隔符 /  \ separatorjava下路径:\ 在Windows下的路径,在java里 \ 是转义字符.需要 \\Str ...

  9. unix/linux共享库(动态库)简介

    一.创建共享库: 1.写源程序 xxx1.c xxx2.c.../*.c(通配符方式) 2.编译源程序,加-fpic生成.o文件 gcc -c -fpic xxx1.c xxx2.c.../*.c(通 ...

  10. Ubuntu 18.04 手动升级内核

    一般情况下,系统正常更新,会自动升级内核到可用的最新版. 查看已安装的内核 $ sudo dpkg -l | grep linux-image 查看当前使用的内核 $ sudo uname -r 查看 ...