头文件 .h
带有指针成员的数据class,为了防止多个指针指向同一块内存地址造成数据混乱,需要进行以下基本的函数重写
以string为例:
- 拷贝构造函数
- 一个参数为本身数据类型的构造函数: 即 A(A a);
- 拷贝赋值函数
- 操作符 = 重载, 将同类型的数据进行赋值操作 A = B
- 析构函数 ~
- 将对象内存等进行回收处理的函数,即将其成员数据销毁
- 拷贝构造函数和拷贝赋值: 一个是构造函数,一个属于操作符的重载,这两个函数都是将数据进行赋值操作。
- 说明:为什么带有指针的class必须要重写拷贝构造和拷贝赋值函数,并重写析构函数。
1. 成员数据的拷贝:带有指针的成员需要将指针指向的数据进行拷贝操作,而不是将指针本身进行拷贝复制。以保证赋值之后的数据操作和原始数据是两个不同的对象。
2. 析构函数: 将带有指针的成员执行的内存销毁,避免内存泄漏。
3. 以上三个函数即使不进行显示重写,编译器也会默认匹配一个,编译器默认匹配的函数将知识对表面的数据类型或者指针本身进行复制操作。这样会导致复制之后的对象和原始对象将享有同一块内存空间的数据,发生异常。
内存
- 栈
在函数体内声明的任何变量,其所使用的内存块都来自于栈 - 堆
由操作系用提供的一块全局的内存空间,程序可以动态分配其所使用的内存空间。例如使用new 关键字创建的对象都属于堆内存空间。 - static 对象:
使用static 修饰的对象,在生命在作用域结束之后依然可以存在的对象,其声明周期与程序声明周期想用 - global 对象
由global修饰的对象,其声明周期与程序生命周期相同。 - 内存泄漏:
即指针死亡之后,其所指向的内存空间没有被有效的销毁,导致程序可能存在的异常情况。 - new 操作符:
用于分配内存并创建对象。
1、首先,分配内存空间
2、其次,调用对象的构造函数,创建对象
3、其后, 对象的使用
4、再次,调用析构函数
5、最后,销毁内存空间,释放内存。 - 数组new和数组del一定是匹配的
String * p = new String[3];
delete[] p // 如果使用delete p 则只会销毁p指向的第一个内存,因为不提供[] 符号,delete 不知道是销毁的p对象,还是[]p 对象。
#ifndef MyString_hpp
#define MyString_hpp
#include <stdio.h>
class MyString{
public:
//构造函数
MyString(const char* cstr=0);
//拷贝构造函数
MyString(const MyString& str);
//拷贝赋值函数,一种操作符的重载方式
MyString& operator=(const MyString& str);
//析构函数
~MyString();
//获取数据
char* get_c_char() const {return m_data;}
private:
char * m_data;
};
#endif /* MyString_hpp */
源文件
#include "MyString.hpp"
#include <string.h>
//拷贝构造函数
inline MyString::MyString(const char* cstr){
/**
MyString s1();
MyString s2("hello")
判断参数cstr是否为空,不为空进行拷贝复制,否则创建一个空字符串
*/
if (cstr){
//字符串内存大小分配
m_data = new char[strlen(cstr)+1];
//在分配的内存中进行数据拷贝复制
strcpy(m_data,cstr);
}else{
//c,c++ 字符串以\0结尾
m_data = new char[1];
*m_data = '\0';
}
}
//拷贝构造函数
inline MyString::MyString(const MyString& str){
m_data = new char[strlen(str.m_data)+1];
strcpy(m_data,str.m_data);
}
//拷贝赋值函数
inline MyString& MyString::operator=(const MyString& str){
//字符串参数自我检测
/**
如果是自身拷贝复制,表示两者是同一个对象,那么直接返回本身即可;
*/
if (this == &str){
return *this;
}
//在拷贝之前,应该将原有的字符串对象的数据进行清空,内存空间进行销毁
delete [] m_data;
//重新进行内存的分配及数据复制
m_data = new char[strlen(str.m_data)+1];
strcpy(m_data,str.m_data);
return *this;
}
//析构函数
inline MyString::~MyString(){
delete [] m_data;
}
测试使用
#include <iostream>
#include "complex.hpp"
#include "MyString.cpp"
int main(int argc, const char * argv[]) {
MyString stringA("hello");
MyString stringB(stringA);
MyString stringC = stringB;
std::cout << stringA.get_c_char();
std::cout << stringB.get_c_char();
std::cout << stringC.get_c_char();
return 0;
}