类的动态内存分配
来源:互联网 发布:淘宝发布宝贝图片尺寸 编辑:程序博客网 时间:2024/05/20 09:21
1.静态类成员:
private: char * str; int length; static int objectNum; //静态数据成员,为所有的对象所共享上例中的objectNum就是静态类成员,它是所有对象所共享的,如下图:
在上例中,创建了三个对象,内存会给每个对象都分配数据单元用来存储Str和Len,但是不会为每个对象都创建num_strings,在内存中只会创建一个num_strings,供所有对象共享。静态类数据成员的初始化不是在类的声明文件中进行的,而是在类的函数定义文件中进行的。如在StringBad.cpp文件中初始化,而不是在StringBad.h文件中初始化。
2.特殊成员函数:
●默认构造函数:如果没有定义构造函数,就会自动生成。
●默认析构函数:如果没有定义析构函数,就会自动生成。
●复制构造函数:当用一个对象初始化另外一个对象时,如果我们没有专门定义复制构造函数,则会自动生成复制构造函数,详解见下面。
●赋值运算符:当用一个对象初始化另外一个对象时,如果我们没有专门定义赋值运算符,则会自动生成赋值运算符,详解见下面。
●地址运算符
3.复制构造函数:
class StringBad{ private: char * str; int length; static int objectNum; //静态数据成员,为所有的对象所共享 public: StringBad(); //默认构造函数 StringBad(const char * s); //构造函数 ~StringBad(); //析构函数 friend ostream & operator<<(ostream & os, const StringBad & sb);};
int StringBad::objectNum = 0; //静态数据成员StringBad::StringBad() //默认构造函数{ length = 4; str = new char[4]; strcpy(str, "c++"); objectNum++; cout << "Object" << objectNum << ": " << str << " is created." << endl;}StringBad::StringBad(const char * s) //构造函数{ length = strlen(s); str = new char[length + 1]; strcpy(str, s); objectNum++; cout << "Object" << objectNum << ": " << str << " is created." << endl;}StringBad::~StringBad() //析构函数{ objectNum--; cout << str << " is deleted." << endl; delete [] str; cout << objectNum << " objects left." << endl;}ostream & operator<<(ostream & os, const StringBad & sb) //重载<<运算符{ os << sb.str << endl; return os;}
int main(){ StringBad sb1("abcde"), sb2 = sb1; cout << sb1; cout << sb2; cout << endl; return 0;}在上例中,定义了一个类StringBad,在类中定义了一些成员函数,然后使用sb2 = sb1,用sb1来初始化sb2,当用一个对象初始化另外一个对象时,就会调用复制构造函数,此时就调用了复制构造函数。
默认的复制构造函数逐个复制非静态成员(成员复制也成为浅拷贝),复制的是成员的值。如在上例中,其实是将sb1.length赋给sb2.length,sb1.str赋给sb2.str,而对象的str成员存储的是字符串的地址,而不是字符串本身,所以这种浅拷贝是将sb1.str和sb2.str指向同一个地方,所以这种浅拷贝容易出问题,当将sb1.str指向的内容删除时,其实也将sb2.str指向的内容也删除了,再删除sb2.str所指向的内容时就会出错。
所以,此时我们就需要自己定义一个复制构造函数来解决这种问题,将sb1.str和sb2.str指向不同的地方,但这两个地方存储的字符串内容是一样的(也就是深拷贝)。
浅拷贝和深拷贝的区别:浅拷贝是仅仅只拷贝字符串的地址,使两个指针指向同一个地方。深拷贝是拷贝内容到另外一个地方,使另一个指针指向拷贝内容的地方,通过深拷贝两个指针指向的地址就不同,但字符串内容仍是相同的。
浅拷贝示意图:
深拷贝示意图:
此例中我们自己定义一个复制构造函数,使得通过对象初始化,也能使两个对象的str指针指向不同的地址:
StringBad::StringBad(const StringBad & st) //复制构造函数,用于将一个对象用于初始化另外一个对象,如object1 = object2{ objectNum++; length = st.length; str = new char[length + 1]; strcpy(str, st.str); cout << "Object" << objectNum << ": " << str << " is created." << endl;}警告:如果类中包含了使用new初始化的指针成员,则我们自己应定义一个复制构造函数,以复制指向的数据,而不是复制指针,这被成为深拷贝。浅拷贝仅仅只是复制指针的值。
4.赋值运算符:
object2 = object1;当我们使用以上语句用object1对object2进行初始化时,实际是分两步来处理:先使用复制构造函数创建一个临时对象,然后通过复制运算符将临时对象复制到新对象中。在第一步中,我们使用我们自己定义的复制构造函数来进行深拷贝;在第二步中,如果我们不自己定义赋值运算符时,我们进行的会是跟默认的复制构造函数一样的浅拷贝,所以我们在这里需要自己定义赋值运算符进行深拷贝。
这里定义的赋值运算符如下:
StringBad & StringBad::operator=(const StringBad & sb){ if(this == &sb) return *this; delete [] str; length = sb.length; str = new char[length + 1]; strcpy(str, sb.str); return *this;}5.整个项目实例代码:
文件结构:
din.h代码:
#ifndef DIN_H_INCLUDED#define DIN_H_INCLUDED#include <iostream>using namespace std;class StringBad{ private: char * str; int length; static int objectNum; //静态数据成员,为所有的对象所共享 public: StringBad(); //默认构造函数 StringBad(const char * s); //构造函数 ~StringBad(); //析构函数 StringBad(const StringBad & st); //复制构造函数,用于将一个对象用令一个对象来初始化,如object1 = object2 StringBad & operator=(const StringBad & sb); friend ostream & operator<<(ostream & os, const StringBad & sb);};#endif // DIN_H_INCLUDEDdin.cpp代码:
#include <iostream>#include <cstring>#include "din.h"using namespace std;int StringBad::objectNum = 0; //静态数据成员StringBad::StringBad() //默认构造函数{ length = 4; str = new char[4]; strcpy(str, "c++"); objectNum++; cout << "Object" << objectNum << ": " << str << " is created." << endl;}StringBad::StringBad(const StringBad & st) //复制构造函数,用于将一个对象用于初始化另外一个对象,如object1 = object2{ objectNum++; length = st.length; str = new char[length + 1]; strcpy(str, st.str); cout << "Object" << objectNum << ": " << str << " is created." << endl;}StringBad::StringBad(const char * s) //构造函数{ length = strlen(s); str = new char[length + 1]; strcpy(str, s); objectNum++; cout << "Object" << objectNum << ": " << str << " is created." << endl;}StringBad & StringBad::operator=(const StringBad & sb){ if(this == &sb) return *this; delete [] str; length = sb.length; str = new char[length + 1]; strcpy(str, sb.str); return *this;}StringBad::~StringBad() //析构函数{ objectNum--; cout << str << " is deleted." << endl; delete [] str; cout << objectNum << " objects left." << endl;}ostream & operator<<(ostream & os, const StringBad & sb) //重载<<运算符{ os << sb.str << endl; return os;}main.cpp代码:
#include <iostream>#include "din.h"using namespace std;int main(){ StringBad sb1, sb2("abcde"), sb4; StringBad sb3 = sb2; sb4 = sb2; cout << sb1; cout << sb2; cout << sb3; cout << sb4; cout << endl; return 0;}
运行结果:
- 类的动态内存分配
- 动态内存的分配
- 类和动态内存分配,类成员的动态内存分配,new,delete,定位new
- 数组的动态内存分配
- 数组的动态内存分配
- 动态内存的分配问题
- 对象的动态内存分配
- C++的动态内存分配
- c++的动态内存分配
- C++的动态内存分配
- 动态内存分配和类
- 类和动态内存分配
- 类和动态内存分配
- 类和动态内存分配
- 类和动态内存分配
- 静态内存与动态内存的分配
- 用未公开的MFC类加强动态内存分配
- 动态内存分配符的使用
- 如何在Windows环境下的VS中安装使用Google Protobuf完成SOCKET通信
- MySQL存储过程详解 mysql 存储过程
- JAVA识别图形验证码
- hadoop-1.0.0源码编译
- Android Fragment getActivity返回null解决
- 类的动态内存分配
- 二维数组--例题
- 使用Qt和Enginio开发云端程序
- uva111
- 我的软考之路(五)——数据结构与算法(3)之图
- 加载驱动程序的代码
- 字符串分割单词(word break problem)问题几种解法之比较
- office办公软件常见问题汇总
- 解析之网站被惩罚应从哪些方面分析