对象的组织
有了自定义类,或别人定义好的类之后,就可以使用其来创建对象。
其机制与使用int等创建普通变量几乎完全一致。
同样可以通过类创建const对象、指向对象的指针、对象数组,动态对象(new/delete)。
const对象
类对象可以声明为const对象。
因为const对象只能被创建、撤销和只读访问,不允许被改写。
所以, 一般来说,除了构造函数和析构函数,能作用于const对象的成员函数只有const成员函数。
//举例代码:
const Point pt(1, 2);
pt.print();
指向对象的指针
指针中存储:对象所占内存空间的首地址。
//格式:
类名 *指针名 [=初始化表达式];
//初始化表达式是可选的,
//可以通过取地址(&对象名)给指针初始化,
//也可以通过申请动态内存给指针初始化,
//或者干脆不初始化(如置为nullptr),在程序中再对该指针赋值。
//举例代码:
Point pt(1, 2);
Point *p1 = nullptr;
Point *p2 = &pt;
Point *p3 = new Point(3, 4); //构造函数初始化
Point *p4 = new Point[5]; //类数组(堆空间)
p3->print(); //指针直接通过指向访问成员函数,合法
(*p3).print(); //指针通过解引用调用成员函数,合法
对象数组
和标准类型数组相比,对象数组的使用方法并没有什么不同,都有声明、初始化和使用3个步骤。
- 声明:
类名 数组名[对象个数];
//自动调用默认构造函数,或所有参数都是自定义默认值的构造函数。
- 初始化:(也可将声明与初始化同时进行)
//完整书写数组元素个数和类构造内容
Point pts[2] = {Point(1, 2), Point(3, 4)};
//缺省数组元素个数
Point pts[] = {Point(1, 2), Point(3, 4)};
//未将数组所有元素进行初始化
Point pts[5] = {Point(1, 2), Point(3, 4)};
//或者,去掉Point的书写,则( )换成{ }
Point pts[2] = {{1, 2}, {3, 4}};
Point pts[] = {{1, 2}, {3, 4}};
Point pts[5] = {{1, 2}, {3, 4}};
堆对象
用new和delete表达式为对象分配动态存储区。
这里主要讨论如何为对象和对象数组动态分配内存。
//举例代码:
void test()
{
//为对象分配动态内存
Point *pt1 = new Point(11, 12);
pt1->print();
delete pt1;
pt1 = nullptr;
//为对象数组分配动态内存
Point *pt2 = new Point[5]();//5个类对象元素
//赋值方式:
pt2[0] = Point(1, 2); //第一种赋值方法
pt2[1] = {3, 4}; //第二种赋值方法
//打印方式:
pt2->print();
(pt2 + 1)->print();
delete [] pt2;
//使用free去进行释放,会core dumped,
//故不能将new和free混用,应该是new和delete搭配使用
}
单例模式
设计需求
一个类只能创建一个对象。
单例模式是23种 GOF 模式中最简单的设计模式之一,属于创建型模式,它提供了一种创建对象的方式,确保只有单个对象被创建。
应用场景
全局对象,或全局唯一资源,如:日志记录器、网页库、字典库等。
实现步骤:
- 将构造函数和析构函数设置为私有(private),防止在类外部多次创建/撤销多个对象(栈对象可以被多次创建)。
- 将创建/撤销对象的自定义成员函数设置为静态(static)公有(public),创建对象的静态成员函数——返回值为类指针。方便在类外调用静态且唯一的创建/撤销对象自定义成员函数,而且可以直接用类名来调用,不用对象名调用。
- 设置一个接收对象空间地址的j静态(static)指针数据成员 (_pInstance),保证创建/撤销操作只对应1个对象。
举例代码
//举例代码:
class Singleton{
public:
//自定义函数创建对象
static Singleton * getInstance(){ //保证1个类只创建1个对象
//如果指针为空,则代表对象尚未被创建,则要创建对象
if(nullptr == _pInstance){
_pInstance = new Singleton();
}
//如果指针不为空,则代表已有对象,直接返回对象指针。
return _pInstance;
}
//自定义函数撤销对象
static void destroy(){
//如果指针不为空,则代表对象仍然存在,故执行delete语句,防止多次delete。
//如果指针为空,则代表对象不存在了,故没有必要执行delete语句,防止多次delete。
if(_pInstance){
delete _pInstance;
_pInstance = nullptr;
}
}
private:
//将构造函数和析构函数设为私有,防止外部调用构造函数/析构函数从而改变临时的栈对象。
Singleton()
{
cout << "Singleton()" << endl;
}
~Singleton()
{
cout << "~Singleton()" << endl;
}
private:
//全局静态数据成员
static Singleton *_pInstance;
};
//初始化静态数据成员(全局位置)
Singleton *Singleton::_pInstance = nullptr;
int main(void)
{
/* Singleton s1; // error,此时s1是栈对象,可多次创建栈对象,不符合单例模式要求。*/
/* Singleton *ps1 = new Singleton(); // error,此时s1是堆对象,但是指针ps1处于栈空间,也不合适。*/
Singleton *ps1 = Singleton::getInstance();//用自定义函数创建对象。
Singleton *ps2 = Singleton::getInstance();//实际上ps1和ps2指向同一对象。
cout << "ps1 = " << ps1 << endl << "ps2 = " << ps2 << endl;
//开始delete操作
/* delete ps1;//error,未在main函数中进行new操作,直接在main中delete不合适; */
/* delete ps2;//进行一个delete后,实则已经delete掉对象所在空间了,再一次delete就重复了,会core dumped。*/
ps1 -> destroy();//正确做法:用自定义函数删除对象
Singleton :: destroy()//正确做法:用类名直接调用静态static函数
return 0;
}
/* delete ps2;//进行一个delete后,实则已经delete掉对象所在空间了,再一次delete就重复了,会core dumped。*/
ps1 -> destroy();//正确做法:用自定义函数删除对象
Singleton :: destroy()//正确做法:用类名直接调用静态static函数
return 0;
}
|