[c++] 面向对象课程(二)-- 带指针类的设计
时间:2021-07-29
本文章向大家介绍[c++] 面向对象课程(二)-- 带指针类的设计,主要包括[c++] 面向对象课程(二)-- 带指针类的设计使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
class with pointer menbers
string_test.cpp
1 #include "string.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main() 7 { 8 String s1("hello"); 9 String s2("world"); 10 11 String s3(s2); 12 cout << s3 << endl; 13 14 s3 = s1; 15 cout << s3 << endl; 16 cout << s2 << endl; 17 cout << s1 << endl; 18 }
string.h
1 #ifndef __MYSTRING__ 2 #define __MYSTRING__ 3 4 class String 5 { 6 public: 7 String(const char* cstr=0); 8 String(const String& str); 9 String& operator=(const String& str); 10 ~String(); 11 char* get_c_str() const { return m_data; } 12 private: 13 char* m_data; 14 }; 15 16 #include <cstring> 17 18 inline 19 String::String(const char* cstr) 20 { 21 if (cstr) { 22 m_data = new char[strlen(cstr)+1]; 23 strcpy(m_data, cstr); 24 } 25 else { 26 m_data = new char[1]; 27 *m_data = '\0'; 28 } 29 } 30 31 inline 32 String::~String() 33 { 34 delete[] m_data; 35 } 36 37 inline 38 String& String::operator=(const String& str) 39 { 40 if (this == &str) 41 return *this; 42 43 delete[] m_data; 44 m_data = new char[ strlen(str.m_data) + 1 ]; 45 strcpy(m_data, str.m_data); 46 return *this; 47 } 48 49 inline 50 String::String(const String& str) 51 { 52 m_data = new char[ strlen(str.m_data) + 1 ]; 53 strcpy(m_data, str.m_data); 54 } 55 56 #include <iostream> 57 using namespace std; 58 59 ostream& operator<<(ostream& os, const String& str) 60 { 61 os << str.get_c_str(); 62 return os; 63 } 64 65 #endif
注意的点
- string_test.cpp:11拷贝构造,14拷贝赋值
- string.h:8拷贝构造(构造函数接受自己),9拷贝赋值,10析构函数
- 不知道将来要创建的对象多大,所以只放一根指针,再动态创建空间放对象
- 类中带指针,要关注三个特殊函数(Big Three)
- 结束符号“\0”判断字符串结束
- 21判断是否空指针
- 22:new:,动态分配一块内存
- 31-35:delete,析构函数,防止内存泄露,变量离开作用域时自动调用
- 11的get_c_str()是为了配合输出函数
拷贝构造(copy ctor)
- String a("Hello"); String b("World"); b = a;
- 如果没有构造拷贝,会发生b和a的指针都指向“Hello”,“World”没有指针指向,导致内存泄露
- 而且a、b一个改动会影响另一个,别名在编程中是危险的事
- 这种拷贝方式称为“浅拷贝”,是编译器的默认版本
- copy ctor 实现“深拷贝”,创建足够的新空间存放蓝本
- String s2(s1); 与 String s2 = s1; 效果相同
拷贝赋值(copy op =)
- String s1("hello"); String s2(s1); s2 = s1;
- 过程:43删除左值--44开辟新空间--45拷贝右值
- 40-41:检测自我赋值(self assignment),来源端和目的端是否相同
- 这步的意义不只是提高效率,不这样写会出错
- 因为43会把原空间删掉,导致45行复制的时候访问空指针
栈(stack)和堆(heap)
- {Complex c1(1,2);}
- {Complex* p = new Complex(3);
- delete p;}
- stack:存在于某作用域(scope)的一块内存空间,调用函数时,函数本身即形成一个stack用来防止它接受的参数,以及返回地址,离开作用域后,析构函数被自动调用(aoto object)
- heap:system heap,操作系统提供的一块global内存空间,程序可以动态分配(dynamic allocated)从中获得若干区域,使用完后需手动释放空间
- {static Complex c1(1,2);}
- 静态对象,离开作用域后对象仍存在,组用域是整个程序
- 全局对象,写在任何作用域之外(全局作用域之中),也可看做一种静态对象
- new:先分配memory,再调用ctor,分解为以下三个函数
- void* mem = operator new(sizeof(Complex)); // 分配内存,operator new调用malloc(n)
- p = static_cast<Complex*>(mem); // 转型
- p->Complex::Complex(1,2); // 构造函数,Complex::Complex(pc,1,2);
- delete:先调用析构函数,再释放内存
- String::~String(p); // 把字符串里面动态分配的内存删掉(字符串本身只是指针m_data)
- operator delete(p); // 内部调用free(p),删掉字符串本身的指针
new到底分配多少内存
- 调试模式下加上debug header 32byte,正常模式下中间为数据(一根指针4byte),上下为cookies 2*4byte,凑够16的倍数
- 动态分配所得的array
- new []:array new
- delete[]:array delete
- array new 一定要搭配 array delete
- String* p = new String[3]; delete[] p; // 唤起3次dtor
- String* p = new String[3]; delete p; // 唤起1次dtor,另外2个指针指向的动态内存数据无法删除(注意指针是可以删除的)
- 虽然new complex的时候不会产生此问题,但也要注意搭配使用,养成好习惯
参考:
const在函数前面与后面的区别
原文地址:https://www.cnblogs.com/cxc1357/p/12285532.html
- 关于JVM直接内存触发Full GC
- 极客DIY:通过树莓派发送摩斯码
- Hadoop SequnceFile.Writer 压缩模式及压缩库浅析
- Thrift抛直接内存OOM一点解决思路
- 小顶堆Java实现
- Tomcat源码分析一:源码导入
- 如何使用Metasploit对安卓手机进行控制
- 关于MySQL DNS解析探究之二:unauthenticated user
- Thrift Direct Memory OOM问题解决方法
- Mapreduce程序中reduce的Iterable参数迭代出是同一个对象
- 内部威胁那些事儿(二):系统破坏
- 从用户行为去理解内容-item2vec及其应用
- Dubbo与Zookeeper、SpringMVC整合和使用(入门级)
- Websocket HandShake Sec-WebSocket-Accept 生成策略
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux后台运行的几种方式(小结)
- Android 实现ListView的点击变色的实例
- Android播放音乐案例分享
- linux crm部署代码详解
- Android自定义WaveProgressView实现水波纹加载需求
- CentOS8下的root密码快速修改方法
- Android开发之自定义刮刮卡实现代码
- Android ScrollView无法填充满屏幕的解决办法
- Android 监听屏幕是否锁屏的实例代码
- Android实现水波纹控件的方法
- Android中GridView布局实现整体居中方法示例
- Android SharedPreferences四种操作模式使用详解
- Ubuntu18.04下将 磁盘挂载在某目录下
- Android编程之绘图canvas基本用法示例
- Android 编译出错版本匹配问题解决办法