类&对象(一)

来源:互联网 发布:剑网三琴萝捏脸数据 编辑:程序博客网 时间:2024/05/21 06:11

C++中定义一个类,本质上就是定义一个数据结构,以关键字class作为标志

一个典型的类结构定义如下:

class test{    public:        int key1;        int key2;        void get_sum();};
关键字class与struct不同的地方在于,struct默认第一个访问说明符之前的成员是public的,而class则使这些成员为private权限的。

定义类的时候,可以定义成员函数,可以在类里面声明并定义函数体,也可以在类外面使用范围解析运算符::进行说明,例如上述的成员函数可以说明如下:

void test::get_sum(){    return key1+key2;}
定义类之后,就可以进行对象的声明以及访问了,如下:

    test s;    s.key1=1;    s.key2=2;    cout<<s.get_sum();

(1)不要显式调用一个类的构造函数

(2)堆栈中声明结果是一个对象(.调用成员数据或者函数),在堆中声明返回的是一个指针(*().调用,等于->)

(3)堆栈中创建对象的时候,如果调用默认构造函数不需要(),使用后会当成一个函数声明;

但是,在堆中创建的时候,需要带上括号;

(4)显式的默认构造函数:

class_name() {}  或者  class_name()=default;

  (5)复制构造函数

使创建的对象是另一对象的精确副本,如果未编写,编译时会自动生成,使用的是对象的const引用,如下:

class class_name

{

public:

class_name(const class_name& class1);   

}

(6)初始化列表构造函数   #include<initializer_list> 

形如:class_name(initializer_list<T> args) {...}

例如:std::vector<std::string> myVec ={"String 1","String 2","String 3"};

(7)复制和赋值的区别

在对象声明的时候,使用的是复制构造函数,如:

class_name class1(1);

class_name class2(class1);  //使用复制构造函数 

class_name class3=class1; // 使用复制构造函数

已经构建的对象,会使用赋值,其实就是operator=的重载

class_name class4;

class4 = class1;  //使用赋值

(8)动态分配内存(并非真正意义的动态,只是在遇到不同的情况能够进行不同的处理,与vector中的动态扩展内存不是一个概念):有的时候,并不知道对象应该给多大的空间,只是给了一些参数,这个时候就要用动态分配:

例如,有一个点SpreadsheetCell类如下:

class SpreadsheetCell{public:    void setValue(double inValue);    double getValue() const;private:    double mValue;};
现在需要创建一个类,里面可能包含多个点(每个点用两个数值坐标定位),但是具体多少个需要根据参数来决定,那么在进行构造的时候,就应当使用动态分配内存
class Spreadsheet{public:    Spreadsheet(int inWidth,int inHeight);    void setCellAt(int x,int y,const SpreadsheetCell& cell);    SpreadsheetCell& getCellAt(int x,int y);private:    bool inRange(int val,int upper);    int mWidth,mHeight;    //因为数组尺度不同,为了动态分配,采用二维指针替代二维数组    SpreadsheetCell** mCells;};//采用动态分配内存的构造函数Spreadsheet::Spreadsheet(int inWidth,int inHeight):    mWidth(inWidth),mHeight(inHeight){    mcells= new SpreadsheetCell* [mWidth];//先分配二维指针    for(int i=0;i<mWidth;i++)    {        mCells[i]=new SpreadsheetCell[mHeight];//每个一维指针指向一段连续内存的数组    }}

相应的,应该有一个动态删除的析构函数如下:

//采用动态删除的析构函数Spreadsheet::~Spreadsheet(){    for(int i=0;i<mWidth;i++)    {        delete[] mCells[i];//后申请的先删除    }    delete [] mCells;    mCells=nullptr;}
(9)复制的理解:(编译生成的复制构造函数和赋值语句只是表层复制,对于动态分配内存不适用)

初始化一个对象:Spreadsheet s1(4,3);

某个函数调用:func(s1);

这个时候传参是表层复制,只是复制了一个mCells的副本,它与原来的mCells指向同一块地址;对该副本的操作会直接改变对象的内存情况,危险!!

还有一种情况:

Spreadsheet s1(2,2),s2(4,3);

s1=s2;

这样执行之后,s1的指针mCells直接指向s2的内存区域,那么s1本来申请的区域被遗弃!内存泄漏!!

所以:如果在类里面动态分配了内存,就需要自己重新写复制构造函数和赋值运算符,以便于深层的内存复制。

重新定义复制构造函数:

Spreadsheet::Spreadsheet(const Spreadsheet& src){    mWidth = src.mWidth;    mHeight = src.mHeight;    mCells = new SpreadsheetCell*[mWidth];    //先创建底层的内存    for(int i=0;i<mWidth;i++)    {        mCells[i]= new SpreadsheetCell[mHeight];    }    //对底层的内存进行数值拷贝    for(int i=0;i<mWidth;i++)    {        for(int j=0;j<mHeigth;j++)        {            mCells[i][j]=src.mCells[i][j];        }    }}
重载赋值运算符:(因为在赋值的时候已经初始化了,故而需要先释放已分配的内存,否则内存泄漏)

Spreadsheet& Spreadsheet::operator=(const Spreadsheet& rhs){    //自检测,为了赋值的正确性    if(this == &rhs)    {        return *this;    }    //先删除已经分配的内存    for(int i=0;i<mWidth;i++)        delete[] mCells[i];    delete[] mCells;    mCells = nullptr;    //进行拷贝    mWidth = rhs.mWidth;    mHeight = rhs.mHeight;    mCells = new SpreadsheetCell*[mWidth];    for(int i=0;i<mWidth;i++)    {        mCells[i]= new SpreadsheetCell[mHeight];    }    for(int i=0;i<mWidth;i++)    {        for(int j=0;j<mHeigth;j++)        {            mCells[i][j]=rhs.mCells[i][j];        }    }    //该运算符有返回值    return *this;}

(10)   =default控制默认构造函数的生成,显式地指示编译器生成该函数的默认版本

 =delete显式指示编译器不生成函数的默认版本 


上一部分完整代码:

#include <iostream>#include <vector>#include <string>#include<stdexcept>using namespace std;class SpreadsheetCell{public:    void setValue(double inValue);    double getValue() const;private:    double mValue;};void SpreadsheetCell::setValue(double inValue){    mValue = inValue;}double SpreadsheetCell::getValue() const{    return mValue;}class Spreadsheet{public:    Spreadsheet(int inWidth,int inHeight);    Spreadsheet(const Spreadsheet& src);    Spreadsheet& operator=(const Spreadsheet& rhs);    void setCellAt(int x,int y,const SpreadsheetCell& cell);    SpreadsheetCell& getCellAt(int x,int y);    ~Spreadsheet();private:    bool inRange(int val,int upper);    int mWidth,mHeight;    //因为数组尺度不同,为了动态分配,采用二维指针替代二维数组    SpreadsheetCell** mCells;};//采用动态分配内存的构造函数Spreadsheet::Spreadsheet(int inWidth,int inHeight):    mWidth(inWidth),mHeight(inHeight){    mCells= new SpreadsheetCell* [mWidth];    for(int i=0;i<mWidth;i++)    {        mCells[i]=new SpreadsheetCell[mHeight];    }}//采用动态删除的析构函数Spreadsheet::~Spreadsheet(){    for(int i=0;i<mWidth;i++)    {        delete[] mCells[i];//后申请的先删除    }    delete [] mCells;    mCells=nullptr;}bool Spreadsheet::inRange(int val,int upper){    if(val>0&&val<upper)        return true;    else        return false;}void Spreadsheet::setCellAt(int x,int y,const SpreadsheetCell& cell){    if(!inRange(x,mWidth)||!inRange(y,mHeight))        throw std::out_of_range("");    mCells[x][y]=cell;}SpreadsheetCell& Spreadsheet::getCellAt(int x,int y){    if(!inRange(x,mWidth)||!inRange(y,mHeight))        throw std::out_of_range("");    return mCells[x][y];}Spreadsheet::Spreadsheet(const Spreadsheet& src){    mWidth = src.mWidth;    mHeight = src.mHeight;    mCells = new SpreadsheetCell*[mWidth];    //先创建底层的内存    for(int i=0;i<mWidth;i++)    {        mCells[i]= new SpreadsheetCell[mHeight];    }    //对底层的内存进行数值拷贝    for(int i=0;i<mWidth;i++)    {        for(int j=0;j<mHeight;j++)        {            mCells[i][j]=src.mCells[i][j];        }    }}Spreadsheet& Spreadsheet::operator=(const Spreadsheet& rhs){    //自检测,为了赋值的正确性    if(this == &rhs)    {        return *this;    }    //先删除已经分配的内存    for(int i=0;i<mWidth;i++)        delete[] mCells[i];    delete[] mCells;    mCells = nullptr;    //进行拷贝    mWidth = rhs.mWidth;    mHeight = rhs.mHeight;    mCells = new SpreadsheetCell*[mWidth];    for(int i=0;i<mWidth;i++)    {        mCells[i]= new SpreadsheetCell[mHeight];    }    for(int i=0;i<mWidth;i++)    {        for(int j=0;j<mHeight;j++)        {            mCells[i][j]=rhs.mCells[i][j];        }    }    //该运算符有返回值    return *this;}

0 0
原创粉丝点击