C++高级编程----熟悉类和对象

     题目要求:设计一个电子表格,该电子表格有两个类:Spreadsheet和SpreadsheetCell。每个Spreadsheet都包含了若干个SpreadsheetCell,此外SpreadsheetApplication类管理Spread集合。

step1 : 从最小单元SpreadsheetCell了解类和对象

1 编写类定义和类方法

考虑实际电子表格允许存储的对象可以是数字,可以是文本数据。如果接收文本数据,电子表格将转换为数字。简单的

编程实现如下:

SpreadsheetCell.h 类方法定义

#SpreadsheetCell.h
#ifndef SPREADSHEETCELL_H_
#define SPREADSHEETCELL_H_
#include
class SpreadsheetCell
{
    public:
        void setValue(double inDouble);
        void setString(const std::string& inString);
        const std::string& getString() const;
    private:
        double mValue;
        std::string mString;
        std::string doubleToString(double inDouble) const;
        double stringToDouble(const std::string& inString) const;
};
#endif

 SpreadsheetCell.cpp 类方法实现

#SpreadsheetCell.cpp
#include "SpreadsheetCell.h"
#include 
#include 

using namespace std;

void SpreadsheetCell::setValue(double inDouble){
    mString = inDouble;
}

void SpreadsheetCell::setString(const string& inString){
    mString = inString;
    mValue = stringToDouble(inString);
}

const string& SpreadsheetCell::getString() const{
    return mString;
}

string SpreadsheetCell::doubleToString(double inDouble) const{
    ostringstream ostr;
    ostr << inDouble;
    return ostr.str();    
}

double SpreadsheetCell::stringToDouble(const string& inString) const{
    double dValue;
    istringstream istr(inString);
    istr >> dValue;
    if(istr.fail() || !istr.eof()){
        return 0;
    }else{
        return dValue;
    }
}

2 编写对象的创建和使用

    在堆栈中的对象调用.method(args): 

SpreadsheetCell mCell;
mCell.setValue(5.0);
cout << "mString " << mCell.getString() << endl;

    在堆中的对象调用->method(args)

SpreadsheetCell mCell = new SpreadsheetCell();
mCell -> setValue(5.0);
cout << "mStirng " << mCell -> getString() << endl;
delete mCell;
mCell = nullptr;

    二者的主要区别:在堆栈中创建的对象无需手动管理内容,创建的对象内存固定;在堆中创建的对象可以动态分配内存,但必须在创建时使用new表达式(首先通过operator new为SpreadsheetCell对象分配内存,然后为这个对象调用构造函数,此处构造函数使用默认构造函数),在销毁时使用delete表达式(首先调用SpreadsheetCell对象的析构函数,然后调用operator delete释放内存)。 

    在堆中使用对象时,为避免发生内存错误,强烈推荐使用智能指针。

auto mCell = make_unique();
mCell -> setValue(5.0)
cout << "mString " << mCell -> getString() << endl;

3 对象的生命周期:创建、销毁、赋值

    1 编写构造函数

//note the var defination order
SpreadsheetCell::SpreadsheetCell(double inDouble):mValue(inDouble), mString(doubleToString(inDouble)){
}

SpreadsheetCell::SpreadsheetCell(double inDouble){
    setValue(inDouble);
}

SpreadsheetCell::SpreadsheetCell(const std::string& inString){
    setString(inString);
}

在堆栈中调用构造函数:

SpreadsheetCell mCell(5.0);

在堆中调用构造函数:

SpreadsheetCell *mCell = new SpreadsheetCell(5.0);
delete mCell;
mCell = nullptr;
//more efficient way
auto smartmCell = make_unipue(5.0);

    注:无论是在堆中还是在类的对象中声明指针,但没有立即初始化对象,都应将指针初始化为nullptr,如果不赋初值nullptr,此时指针未定义,进而可能导致无法预料或难以诊断的内存错误。

    2 特殊的构造函数——复制构造函数

SpreadsheetCell::SpreadsheetCell(const SpreadsheetCell& src){
    mValue = src.mValue;
    mString = src.mString;
}

    复制构造函数允许所创建的对象是另一个对象的精确副本。如果没有编写复制构造函数,c++会自动生成一个,用源对象相应数据成员的值初始化新对象的每个数据成员,如果数据成员是对象,意味着调用复制构造函数。

    :c++传递函数参数的默认方式是按值传递,这意味着函数或者方法接收某个值或者对象的副本。因此,无论什么时候给函数或者方法传递一个对象时,编译器都会调用新对象的复制构造函数进行初始化。当函数或者方法返回对象时,也会调用复制构造函数,在此情况下,编译器使用复制构造函数创建一个临时的、没有名称的对象。可将传递的参数作为const引用,从而避免复制构造函数的开销。按引用传递只需要复制对象的地址,不需要复制对象的全部内容,因此比按值传递的效率更高,当按引用传递某个对象时,使用对象引用的函数或方法可以修改原始对象,如果只是为了提高效率才使用按引用传递,可将对象设置为const以排除这种可能。

    3 默认析构函数

    当销毁对象时,首先调用析构函数,然后释放对象占用的内存。在析构函数中可以执行对象的清理,如释放动态内存或关闭句柄文件。当堆栈中的对象超出作用域时,意味着当前的函数,方法或者代码块结束,对象被销毁。没有智能指针的帮助,在堆中分配的内存不会自动销毁,必须使用delete删除对象指针,从而调用析构函数,并释放内存。

practice makes perfect!

 

你可能感兴趣的:(C++高级编程)