C++ 类、构造析构、深拷贝
1st,感性理解类的思想,就是把数据和对数据的操作打包在一块儿,设计类的时候要 想好数据部分和 要进行的操作。以下是时间类的示意,时间包含时分秒,Time为构造函数,该类支持的操作就是设置时间和读取时间,static类型记录对象数量,static机制查询相关书籍。
//Time.h
#ifndef Time_h
#define Time_h class Time {
public:
Time(int h = , int m = , int s = );
void SetTime(int, int, int);
void printMilitary( ); //Military style
void printStandard( ); //Standard style
~Time();
static int count;
private:
int hour; //0-23
int minute; //0-59
int second; //0-59
};
#endif // Time_h //Time.cpp
#include <iostream>
#include "time.h"
using namespace std; int Time::count = ; Time::Time(int h, int m, int s) { count++;
hour = h; minute = m; second = s;
} //Time Time::~Time() {
count--;
cout << "~Time is called." << endl;
} //~Time void Time::SetTime(int h, int m, int s) {
hour = ((h >= && h < ) ? h : );
minute = ((m >= && m < ) ? m : );
second = ((s >= && s < ) ? s : );
} //SetTime void Time::printMilitary() { cout << (hour < ? "" : "") << hour << ":"
<< (minute < ? "" : "") << minute << ":"
<< (second < ? "" : "") << second << endl;
return;
} void Time::printStandard() {
cout << ((hour == || hour == ) ? : hour % ) << ":"
<< ((minute < ) ? "" : "") << minute << ":"
<< ((second < ) ? "" : "") << second
<< ((hour < ) ? "AM" : "PM") << endl;
return;
} //main.cpp
#include "time.h" int main() {
Time a(,,);
Time b(, , ); a.printMilitary();
a.printStandard();
b.printMilitary();
b.printStandard(); return ;
}
2nd,构造函数和析构函数,以下代码可以准确示意析构函数调用的时机,觉得不够详细还可以自己继续加入cout语句输出信息。
这个代码的大意就是:class myClass 中还有类型为 classA、classB的数据,它们以初始化列表形式赋值,构造函数调用顺序:ABC,析构函数调用顺序CBA。构造函数分配了内存,析构函数中要记得释放内存。
/***********************************************
Class A Constructor ! x=0
Class B Constructor ! x=0
Class C Constructor !
Class C Destructor !
Class B Destructor !
Class A Destructor ! Class A Constructor ! x=3
Class B Constructor ! x=3
Class C Constructor ! With Initial List Class A Constructor ! x=22
Class B Constructor ! x=65
Class C Constructor ! With Initial List Class C Destructor !
Class B Destructor !
Class A Destructor !
Class C Destructor !
Class B Destructor !
Class A Destructor !
请按任意键继续. . . ************************************************/ //ClassA.h #if _MSC_VER >1000
#pragma once
#endif // class classA {
public:
classA(int = );
virtual ~classA();
}; //classA.cpp
#include "classA.h"
#include <iostream>
using namespace std; classA::classA(int x) {
cout << "Class A Constructor ! x=" << x << endl;
} classA::~classA() {
cout << "Class A Destructor !" << endl;
} //classB.h #if _MSC_VER >1000
#pragma once
#endif // class classB {
public:
classB(int = );
virtual ~classB();
}; //classB.cpp
#include "classB.h"
#include <iostream>
using namespace std; classB::classB(int x) {
cout << "Class B Constructor ! x=" << x << endl;
} classB::~classB() {
cout << "Class B Destructor !" << endl;
} //myClass.h
#include "classA.h"
#include "classB.h" #if _MSC_VER >1000
#pragma once
#endif // class myClass {
public:
myClass(int);
myClass();
myClass(int, int, int);
virtual ~myClass();
private:
int year;
classA objA; //Constructor Turn:A -> B ->C;
classB objB;
}; //myClass.cpp
#include "myClass.h" #include<iostream>
using namespace std; myClass::myClass(int y) {
cout << "Class C Constructor !" << endl;
year = y;
} myClass::myClass():objA(),objB() {
cout << "Class C Constructor ! With Initial List" << endl;
} myClass::myClass(int y, int a, int b):year(y),objA(a),objB(b) {
cout << "Class C Constructor ! With Initial List" << endl; } myClass::~myClass() {
cout << "Class C Destructor !" << endl;
} //main.cpp
#include "myClass.h"
#include<iostream>
int main() {
myClass * pmyobj;
pmyobj = new myClass(); delete pmyobj; std::cout << std::endl << std::endl; myClass myobj;
std::cout << std::endl << std::endl; myClass myobj2(, , );
std::cout << std::endl << std::endl;
return ;
}
3rd,拷贝构造函数,首先意识到有系统会有默认拷贝构造函数存在,就像有默认的构造函数和析构函数一样。本科时候用VC 6.0编程,拷贝构造函数和operator = 必须要自己定义,尤其是构造函数中有new 的情况。刚刚用了VS2015试了一个程序,发现默认的拷贝构造函数在值类型时传递的是拷贝的值,而对于char * ,则与原对象的值共享,如果析构了原对象,会引发错误(野指针),debug assertion failed,所以还是要自己定义拷贝构造函数。这里谈下浅拷贝和深拷贝。浅拷贝一句话:不涉及内存分配,传递值类型。深拷贝:要分配内存复制值。
这是浅拷贝 - 用默认拷贝构造函数,会有错误的。
//myClass.h #if _MSR_VER > 1000
#pragma once
#endif #include <string> class myClass {
public:
myClass(char * = NULL, int = );
void print();
~myClass();
private:
char * name;
int year;
}; //myClass.cpp #include "myClass.h"
#include <iostream>
using namespace std; myClass::myClass(char *n, int y) {
year = y; name = NULL;
if (n) {
int len = strlen(n) + ;
name = new char[len];
strcpy_s(name, len, n);
}
} //myClass myClass::~myClass() {
if (name) delete [] name;
} //~myClass void myClass::print() {
cout << name << "--" << year << endl;
} //main.cpp #include "myClass.h"
#include<iostream>
using namespace std; int main() {
int a = , b(a);
myClass sd1("ABC", a), sd2("XYZ", b + ); myClass sd3(sd1); //
sd1.print();
sd2.print(); return ;
}
深拷贝代码如下,加入进去就不会有错误。
//myClass.h class myClass {
public:
myClass(const myClass & a);
}; //class myClass //myClass.cpp myClass::myClass(const myClass & a) {
year = a.year; name = NULL;
if (a.name) {
int tmplen = strlen(a.name) + ;
name = new char[tmplen];
strcpy_s(name, tmplen, a.name);
}
} //main.cpp
int a = , b(a);
myClass sd1("ABC", a);
myClass sd2(sd1); //deep copy!
sd1.print();
sd2.print();
深拷贝函数与类名相同,参数类型为对象的引用,看作是特殊的构造函数吧,注意,并不是所有类都要定义拷贝构造函数,例如网络链接中,同时,此时,operator = 也一并禁止掉吧。
C++ 类、构造析构、深拷贝的更多相关文章
- C++类构造析构调用顺序训练(复习专用)
//对象做函数参数 //1 研究拷贝构造 //2 研究构造函数,析构函数的调用顺序 //总结 构造和析构的调用顺序 #include "iostream" using namesp ...
- Effective C++ ——构造/析构/赋值运算符
条款五:了解C++默认编写并调用那些函数 是否存在空的类? 假设定义类为class Empty{}:当C++编译器处理过后会变成如下的形式: class Empty{ Empty(){} ~Empty ...
- EffectiveC++ 第2章 构造/析构/赋值运算
我根据自己的理解,对原文的精华部分进行了提炼,并在一些难以理解的地方加上了自己的"可能比较准确"的「翻译」. Chapter 2 构造 / 析构 / 赋值 条款 05:了解C++ ...
- Effective C++ —— 构造/析构/赋值运算(二)
条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...
- 《Effective C++》第2章 构造/析构/赋值运算(1)-读书笔记
章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...
- 《Effective C++》读书笔记 被你忽略的关于构造析构赋值
如果程序员没有定义,那么编译器会默认隐式为你创建一个copy构造函数,一个copy赋值操作符,一个析构函数.另外如果你没有声明任何构造函数,编译器会为你声明一个default构造函数. 但是只有当这些 ...
- HexoC++第04课 构造析构.md
C++第04课 构造析构.mdhtml {overflow-x: initial !important;}#write, body { height: auto; } #write, #write h ...
- C++ map.insert 传参类型不同,构造/析构次数不同
1. 传参方式 使用 insert 为 map 插值时,insert 的传参包含以下几种可能: make_pair 生成对象 pair(key_type, value_type) 生成对象 pair( ...
- c++构造析构顺序
class A { public: A(){ cout << "constrcut A" << endl; }; ~A(){ cout << & ...
- python模块之HTMLParser(原理很大程度上就是对类构造的熟练运用)
# -*- coding: utf-8 -*- #python 27 #xiaodeng #python模块之HTMLParser(原理很大程度上就是对类构造的熟练运用) import HTMLPar ...
随机推荐
- 添加 index_combine hint的索引
想试验一下 index_combine这个hint,于是做了如下试验. 1.创建一个具有若干index的表 SQL> create table test as select object_id, ...
- [原创]DC-DC输出端加电压会烧毁
在调试智能钥匙连续开锁出现故障的问题排查过程中,为了对比模拟开关TS5A3166对于开锁数据通信的影响,尝试短接模拟开关的输入输出脚,未曾想乌龙了一把,错把DC-DC芯片输入输出短接了(两者都是S ...
- Google-GLog编译以及使用
心血来潮要去看开源代码,看到公司的日志库是在google-glog开源库上二次封装的,那就先撸glog吧. 1. 下载源码 一条命令取源码:git clone github.com/google/g ...
- 【树莓派】【转】利用USB网卡配置树莓派为无线热点
由于Wifi很慢,基本不可用:树莓派有无线网卡,恰好看到有文章用树莓派来做无线热点,利用树莓派来共享无线网络.比较有用,转发后续尝试. 本文转自:https://www.embbnux.com/201 ...
- 如何自定义ReportDesigner的向导界面(WIN)
https://www.devexpress.com/Support/Center/Example/Details/T140683
- php操作ini配置文件
有些配置化的数据放到配置文件可以方便管理,比如数据库信息,路由信息,先建立配置文件,test.ini [database_setting] host=127.0.0.1 user=root passw ...
- Linux安装时内存如何分区的相关问题
Linux系统安装时内存如何分区:Linux系统必须的分区是根分区(/)和swap交换分区.普通用户一般分三个区,一个根分区(/),一个家目录(home分区),一个交换分区(swap分区),以80G的 ...
- springcloud(第三篇)springcloud eureka 服务注册与发现 *****
http://blog.csdn.net/liaokailin/article/details/51314001 ******************************************* ...
- 采用MANIFEST.MF之jar报错ClassNotFoundException解法
检查n多遍也试了n多次,证明下面是MANIFEST.MF文件正确写法: Manifest-Version: 1.0 Premain-Class: cn.yandz.monitor.SizeOfObje ...
- null
期末考备考最后三天. 加油,把这学期学的知识给它搞透了.