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 ...
随机推荐
- ubuntu安装
今天在win10下安装Ubuntu,结果没经验导致win10找不回来了,我再好好整理些思路 安装前要做一个ghost,万一出现问题可以用来恢复系统! 1,我使用USB Installer 在http: ...
- Android SDK Tools 更新
C:\WINDOWS\system32\drivers\etc\hosts 文件用记事本打开后 添加下面的 74.125.237.1 dl-ssl.google.com
- Analyzer中进行货币转换
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- python进阶(四)---需要了解的魔法方法
以下内容,源于个人理解所得,纯属臆测,爱信不信:-D.欢迎大家留言讨论指正. 1.__new__魔法方法: 原型:__new__(cls, *args, **kwargs) 说明:__new__魔法方 ...
- Thread
问题:编写一个能提现多线程的例子?假设有t1,t2两个线程,如何保证t2线程在t1线程执行完后再执行? package cn.changb.thread; public class MyThread ...
- iBatis框架基本使用
iBatis框架是Java持久层开发框架,说白了就是前人写了一部分代码(针对数据库操作),我们要做的就是再次开发,拿来框架直接使用. 我们自己开发时,dao层的sql语句都是写死在程序中的,如果查询条 ...
- js /jquery停止事件冒泡和阻止浏览器默认事件
1>js阻止冒泡事件 var el = window.document.getElementById("a"); el.onclick = function (e) { // ...
- OAM
OAM -- Operation Administration and Maintenance[ˈmentənəns]. 根据运营商网络运营的实际需要,通常将网络的管理工作划分为3大类:操作(Oper ...
- java: Thread 和 runnable线程类
java: Thread 和 runnable线程类 Java有2种实现线程的方法:Thread类,Runnable接口.(其实Thread本身就是Runnable的子类) Thread类,默认有ru ...
- java数据库连接池技术原理(浅析)
在执行数据库SQL语句时,我们先要进行数据连接:而每次创建新的数据库的连接要消耗大量的资源,这样,大家就想出了数据库连接池技术.它的原理是,在运行过程中,同时打开着一定数量的数据库连接,形成数据连接池 ...