this指针和重构

this指针

this指针用来指向当前对象

class Point
{
public:
Point(int ix = 0, int iy = 0)
:_ix(ix)
, _iy(iy)
{
cout << "Have done Create" << ' '<<_ix<<' '<<_iy<<endl;
}
void print()
{
cout<<this->_ix<<' '<<this->_iy<<endl;
}
private:
int _ix;
int _iy;
};

每一个非静态修饰的成员函数都有隐含的this指针(为什么静态没有,后文会说明)

this指针会作为函数成员的一个隐藏的第一个参数,在编译时会自动填充,不需要我们自己填补(会报错)

Point p1(1, 1);
p1.print();//== Point::print(&p1);

operator重构

重构(我自己定义的词,根据重载推演的,准确翻译叫什么我也不知道)就是对一个已定义的函数,操作运算符重新定义,重新构造一遍

重构对当前类赋值运算符重构(即重构深拷贝)

class Point
{
public:
Point(int ix = 0, int iy = 0)
:_ix(ix)
, _iy(iy)
{
cout << "Have done Create" << ' '<<_ix<<' '<<_iy<<endl;
}
Point(const Point& p)//浅拷贝
:_ix(p._ix)
,_iy(p._iy)
{
cout << "Have done Copy" << endl;
}
//赋值运算符函数,系统自动提供,可以重构
Point& operator = (const Point& p)
{
_ix = p._ix;
_iy = p._iy;

cout << "Have done operator=" << endl;
return *this;
}
void print()
{
cout << this->_ix << ' ' << this->_iy << endl;
}

private:
int _ix;
int _iy;
};

深拷贝的两种写法

Point p2(2,2);

p2 = p1;
p2.operator = (p1);

完整代码

#include <iostream>

using std::cout;
using std::endl;

class Point
{
public:
Point(int ix = 0, int iy = 0)
:_ix(ix)
, _iy(iy)
{
cout << "Have done Create" << ' '<<_ix<<' '<<_iy<<endl;
}
Point(const Point& p)
:_ix(p._ix)
,_iy(p._iy)
{
cout << "Have done Copy" << endl;
}
//赋值运算符函数,系统自动提供,可以重构
Point& operator = (const Point& p)
{
_ix = p._ix;
_iy = p._iy;

cout << "Have done operator=" << endl;
return *this;
}
void print()
{
cout << this->_ix << ' ' << this->_iy << endl;//每一个成员函数都有一个隐藏的this指针
//this指针指向当前的对象
}

private:
int _ix;
int _iy;
};
void test0()
{
Point p1(1, 1);

//this指针作为成员的隐藏的第一个参数
//编译器在编译时自动加上
p1.print();//== Point::print(&p1);

Point p2(2, 2);
p2 = p1;
p2.operator = (p1);//两种写法完全相同
}
int main()
{
test0();
return 0;
}

数据成员修饰

const数据成员

const初始化

一般在定义构造函数的时候,通常去初始化一堆数据成员,防止运行出错

Point(int ix,int iy,int iz)
:_ix(ix)
,_iy(iy)
,_iz(iz)
//引用成员必须在此处初始化
{
cout << "Have done structure" << endl;
}

可以在private内部 声明数据成员时用const修饰

const  int _ix = 10;
//const int _ix = 10;//为了避免初始化冗余,直接用const初始化数据成员
const int _iy = 10;

此时即使不使用初始化列表(有参构造函数),对象创建时他的数据成员也已经被初始化了

class Point
{
public:

Point() = default;//简便定义默认构造函数

Point(const int& ix,const int& iy)
:_ix(ix)
,_iy(iy)
//引用成员必须在此处初始化
{
cout << "Have done structure" << endl;
}
void print()
{
cout << _ix << ' ' << _iy << endl;
}
private:
const int _ix = 10;
//const int _ix = 10;//为了避免初始化冗余,直接用const初始化数据成员
const int _iy = 10;
//int& _ref;
};

int main()
{
Point p;//无参时调用默认构造函数
p.Print();
Point p1(1, 2);
p1.print();
const Point p2(1, 2);
p2.print();
}

输出结果
···
10 10
Have done structure
1 2
Have done structure
1 2
···

const成员函数

const修饰的成员函数只能读取数据成员不能进行修改,不允许在内部改变
const修饰对象只能调用const成员函数
非const修饰的对象可以调用const成员函数,也可以调用非const成员函数

const成员函数形式

void print() const
{
cout<<_ix<<' '<<_iy<<endl;
}

const在对象应用的完整代码

#include <iostream>

using std::cout;
using std::endl;

class Point
{
public:

Point() = default;//简便默认构造函数

Point(const int& ix,const int& iy)
:_ix(ix)
,_iy(iy)
//引用成员必须在此处初始化
{
cout << "Have done structure" << endl;
}

//const成员函数
void print() const//const成员函数只能读取数据成员,不能修改
{
//数据成员不允许在const成员函数内部改变,只能读取
//_ix = 10;
cout << _ix << ' ' << _iy << endl;
}

//非const成员函数与const修饰成员函数重名时可以构成重载
void print()
{
cout << _ix << ' ' << _iy << endl;
}
//非const对象可以调用非const成员函数和const成员函数
//const对象只能调用const成员函数
private:
const int _ix = 10;
//const int _ix = 10;//为了避免初始化冗余,直接用const初始化数据成员
const int _iy = 10;
//int& _ref;
};
class Line
{
public:
Line(int x1, int y1, int x2, int y2)
:_pt1(Point(x1,y1))
,_pt2(Point(x2,y2))
{
cout << "Line(x1,y1,x2,y2)" << endl;
}
//默认情况下,类数据成员初始化会调用无参构造函数
void LinePrint()
{
_pt1.print();
_pt2.print();
}
private:
Point _pt1;
Point _pt2;
};
void test0()
{
Point p;
p.print();
Point p1(1, 2);
p1.print();
const Point p2(1, 2);
p2.print();

Line l1(1, 2, 3, 4);
l1.LinePrint();
}
int main()
{
test0();

return 0;
}

static数据成员

static修饰数据成员

static修饰的数据成员被整个类所有对象所共享
static数据成员分布在全局静态区,不占用对象的存储空间
static数据成员需要在类之外,全局区初始化

class Computer
{
public:
private:
char* _name;
int _price;
static double TotalPrice;
};

//静态数据成员初始化
double Computer::_TotalPrice = 0;

int main()
{
return 0;
}

假设有Computer类,有若干Computer对象,求所有对象的总价,就可以用static修饰的数据成员去求得

静态数据成员需要注意的点

如果不存在静态数据成员,类的定义可以如下写

class Computer
{
public:
Computer(const char* brand, const int& price)
:_brand(new char[strlen(brand) + 1]())
, _price(price)
{
strcpy(_brand, brand);
cout << "Have done structure!" << endl;
}
void release()
{
//cout << &_brand << endl;
delete[] _brand;
_brand = nullptr;
}
~Computer()
{
if (_brand) release();
cout << "Have do ne Delete" << endl;

}

void swap(Computer& p)
{
std::swap(this->_brand, p._brand);
std::swap(this->_price, p._price);
}

Computer(const Computer& p)
:_brand(new char[strlen(p._brand) + 1]())
, _price(p._price)
{
strcpy(_brand, p._brand);
}
Computer& operator = (const Computer& p)
{
if (this == &p) return *this;

Computer tmp(p._brand, p._price);

swap(tmp);

return *this;
}

void print()
{
cout << _brand << ' ';
cout << _price << endl;
}

private:
char* _brand;
int _price;
};

当有了静态数据成员TotalPrice时,函数构造,拷贝,折构时都需要对该变量特殊处理

class Computer
{
public:
Computer(const char* brand, const int& price)
:_brand(new char[strlen(brand) + 1]())
, _price(price)
{
strcpy(_brand, brand);
_TotalPrice += _price; //记录总价
cout << "Have done structure!" << endl;
}
void release()
{
//cout << &_brand << endl;
delete[] _brand;
_brand = nullptr;
}
~Computer()
{
if (_brand) release();
_TotalPrice -= _price;//对象销毁,总价减少
cout << "Have do ne Delete" << endl;

}

void swap(Computer& p)
{
std::swap(this->_brand, p._brand);
std::swap(this->_price, p._price);
}

Computer(const Computer& p)
:_brand(new char[strlen(p._brand) + 1]())
, _price(p._price)
{
_TotalPrice += _price;
strcpy(_brand, p._brand);
}
Computer& operator = (const Computer& p)
{
if (this == &p) return *this;

//原先的成员需要去掉
_TotalPrice -= _price;

Computer tmp(p._brand, p._price);

swap(tmp);

//新拷贝的price嫁过来
_TotalPrice += _price;

return *this;
}

void print()
{
cout << _brand << ' ';
cout << _price << endl;
}


private:
char* _brand;
int _price;
static double _TotalPrice;
};

静态成员函数

1.静态函数成员内部只能访问静态数据成员和静态函数成员
2.不能访问非静态数据成员和函数成员
3.静态成员函数内部没有隐含的this指针(即不能指向非静态数据成员)

静态函数成员形式

static void printTotal()
{
cout << _TotalPrice << endl;
}

static在对象应用中的完整代码

#include <iostream>

using std::cout;
using std::endl;

class Computer
{
public:
Computer(const char* brand, const int& price)
:_brand(new char[strlen(brand) + 1]())
, _price(price)
{
strcpy(_brand, brand);
_TotalPrice += _price; //记录总价
cout << "Have done structure!" << endl;
}
void release()
{
//cout << &_brand << endl;
delete[] _brand;
_brand = nullptr;
}
~Computer()
{
if (_brand) release();
_TotalPrice -= _price;//对象销毁,防止拷贝多余出来price
cout << "Have do ne Delete" << endl;

}

void swap(Computer& p)
{
std::swap(this->_brand, p._brand);
std::swap(this->_price, p._price);
}

Computer(const Computer& p)
:_brand(new char[strlen(p._brand) + 1]())
, _price(p._price)
{
_TotalPrice += _price;
strcpy(_brand, p._brand);
}
Computer& operator = (const Computer& p)
{
if (this == &p) return *this;

//原先的成员需要去掉
_TotalPrice -= _price;

Computer tmp(p._brand, p._price);

swap(tmp);

_TotalPrice += _price;

return *this;
}

void print()
{
cout << _brand << ' ';
cout << _price << endl;
}

static void printTotal()
{
cout << _TotalPrice << endl;
}

private:
char* _brand;
int _price;
static double _TotalPrice;
//静态数据成员被整个类的所有对象共享
//存放在全局静态区,并不占用对象的存储空间
//静态变量需要在类之外初始化
};

double Computer::_TotalPrice = 0;//不用再加一个static,且要在全局区去定义

//静态成员函数内部只能访问静态数据成员和成员函数
//静态成员函数内部不能访问非静态的数据成员和成员函数
//静态成员的函数列表中没有隐含的this指针

void copy(Computer p)
{
p.print();
p.printTotal();
}
void test1()
{
Computer p1("abc", 4999);
Computer p2 = p1;

p1.print();
p1.printTotal();

copy(p2);


p1.print();
p1.printTotal();

//静态成员函数能通过类名直接调用
Computer::printTotal();
}
int main()
{
test1();

return 0;
}

单例模式

特点:一个类只能生成一个对象,且是唯一的对象

单例模式的定义方法

1.将构造函数私有化
创建的对象就既不能是栈对象,也不能是全局/静态对象,只能是堆对象(因为new/malloc出来唯一的对象可以用地址访问)

class SingleClass
{
public:
private:
SingleClass() {cout<<"Have done create!"<<endl;}
};

2.在类中定义一个静态指针指向该类

class SingleClass
{
public:
private:
SingleClass() {cout<<"Have done create!"<<endl;}
static SingleClass* _pInstance;
};

//static数据成员初始化在全局
SingleClass* Singleclass::_pInstace = nullptr;

3.定义一个返回值为静态指针的静态函数
非静态函数必须有对象才能调用,static进行修饰后可以直接调用,就能得到唯一对象的地址

class SingleClass
{
public:
static SingleClass* getInstance()
{
if(_pInstance = nullptr)//保证不会多次new,保证对象的唯一
_pInstance = new SingleClass;
return _pInstance;
}
private:
SingleClass() {cout<<"Have done create!"<<endl;}
static SingleClass* _pInstance;
};

SingleClass* Singleclass::_pInstace = nullptr;

单例对象的销毁

在类内部定义一个函数实现对唯一对象的delete

class SingleClass
{
public:
static SingleClass* getInstance()
{
if(_pInstance = nullptr)//保证不会多次new,保证对象的唯一
_pInstance = new SingleClass;
return _pInstance;
}
static void release()
{
if(_pInstance) delete _pInstance;
}
private:
SingleClass() {cout<<"Have done create!"<<endl;}
static SingleClass* _pInstance;
};

完整代码

#include <iostream>

using std::cout;
using std::endl;

//单例模式
//一个类只能生成一个对象,且是唯一的对象

//1.将构造函数私有化,唯一的对象既不能是栈对象,也不能是全局/静态对象
//2.在类中定义一个静态指针指向该类
//3.定义一个返回值为类指针的静态函数
//
class SingleClass
{
public:
static SingleClass* getInstance()//获取实例
//非静态成员函数必须有对象才能调用,因此用static修饰使得无需对象(或者说是单例模式可用)
{

if (_pInstance == nullptr)//保证不会进行多次new,保证对象的唯一
_pInstance = new SingleClass;
return _pInstance;//在类中可以直接调用构造函数,因此可以进行new操作
}

static void release()
{
if(_pInstance)
delete _pInstance;
}


private:
SingleClass() { cout << "Have done create!" << endl; }

~SingleClass()//禁止外部delete
{ cout << "Have done delete!" << endl; }

static SingleClass* _pInstance;//静态数据成员初始化在类外部
};

SingleClass* SingleClass:: _pInstance = nullptr;

//SingleClass s3;

void test()
{
//SingleClass s2;
//SingleClass* sc1 = new SingleClass; new表达式也会调用构造函数
SingleClass* sc2 = SingleClass::getInstance();
}
int main()
{
cout << "abc" << endl;
test();

//SingleClass s1;
SingleClass* sc3 = SingleClass::getInstance();//因为只有唯一的对象,所以只会创建一次

SingleClass::release();//delete操作时调用析构函数

return 0;
}