类的动态内存分配

来源:互联网 发布:淘宝发布宝贝图片尺寸 编辑:程序博客网 时间: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_INCLUDED
din.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;}

运行结果:




0 0
原创粉丝点击