14.C++ 特殊类与设计模式
特殊类设计
- 1. 不能被拷贝的类
- 2. 只能在堆上创建对象的类
- 3. 只能在栈上创建对象的类
- 4. 设计一个类,不能被继承
- 5. 单例模式
- 概念
- 饿汉模式
- 懒汉模式
- 6. 模版方法模式
- 7. 工厂模式
- 8. 观察者模式
1. 不能被拷贝的类
拷贝只会出现在两个场景中:拷贝构造和拷贝赋值。因此让该类无法调用这两个函数即可(两种方法)
- 令这两个函数私有
- 使用C++11关键字delete
class A
{
public:A(){}A(const A& a) = delete; //删除函数A& operator=(const A& a) = delete;
private://A(const A& a) {} //私有化//A& operator=(const A& a) {}
};
2. 只能在堆上创建对象的类
- 构造函数私有,拷贝构造私有
- 提供一个静态成员函数,在此函数中完成在堆上创建对象
class A
{
public:static A* CreateFronHeap(){return new A;}
private:A(const A& a) {} //私有化A(){}
};int main()
{A* a = A::CreateFronHeap();cout << a << endl;return 0;
}
3. 只能在栈上创建对象的类
- 把operator new和delete这些禁用掉
- 提供一个静态成员函数,在此函数中完成在栈上创建对象
- 以下为最初设想的逻辑
class A
{
public:static A CreateFronStack(){return A();}void* operator new(size_t size) = delete;void operator delete(void* ptr) = delete;void* operator new[](size_t size) = delete;void operator delete[](void* ptr) = delete;
};int main()
{A a = A::CreateFronStack();cout << &a << endl;return 0;
}
但尽管如此,由于构造函数是公有,所以还是有方法让这个类型在堆上创建(创建个新类,让A做成员)
class foo
{
public:A a;
};
int main()
{A a = A::CreateFronStack();cout << &a << endl;foo* f = new foo;cout << f << endl;cout << &f->a << endl;return 0;
}
因此,构造函数必须是私有(但是静态成员函数无法访问类内部成员);再者根据单例模式的灵感,可以变相的通过一个静态变量调用成员函数再调用构造函数
class A
{
public:static A CreateFronStack(){return _self.Create();}A Create(){return A();}void* operator new(size_t size) = delete;void operator delete(void* ptr) = delete;void* operator new[](size_t size) = delete;void operator delete[](void* ptr) = delete;
private:A(){}static A _self;
};
A A::_self = A(); //定义静态变量来调用成员函数int main()
{A a = A::CreateFronStack();A b = A::CreateFronStack();cout << &a << endl;cout << &b << endl;return 0;
}
4. 设计一个类,不能被继承
- 构造函数私有
class A
{
private:A(){}
};
- C++11的final关键字
class A final
{};
class B : public A //提示:不能将A作为基类
{};
5. 单例模式
概念
一个类只能创建一个对象,该模式保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享
饿汉模式
程序启动时就创建一个唯一的实例对象
优点:简单
缺点:可能导致进程启动慢,且如果有多个单例对象实例启动顺序不确定
class Single
{
public:static Single* GetInstance(){return &_sIns;}
private:Single(){}Single(const Single& sl) = delete;Single& operator=(const Single& sl) = delete;static Single _sIns;
};
Single Single::_sIns; //在程序入口之前就完成单例对象实例化int main()
{Single* sl = Single::GetInstance();return 0;
}
懒汉模式
程序第一次调用时才实例化对象
优点:进程启动无负载,多个单例实例启动顺序自由控制
缺点:复杂
class Single
{
public:static Single* GetInstance(){if (_sIns == nullptr) //如果单例不在,再加锁{lock_guard<mutex> lock1(_mtx);if (_sIns == nullptr) //只有一个线程会进来,其他线程阻塞在lock{_sIns.reset(new Single());}}return _sIns.get();}
private:Single(){}Single(const Single& sl) = delete;Single& operator=(const Single& sl) = delete;static unique_ptr<Single> _sIns; //单例对象static mutex _mtx; //单例对象创建时需要锁
};
unique_ptr<Single> Single::_sIns = nullptr;
mutex Single::_mtx;int main()
{Single* sl = Single::GetInstance();return 0;
}
6. 模版方法模式
模版方法定义了一个大致的框架(父类),后续继承的子类可以重新定义这个框架的步骤。
如下代码
- 定义了做作业的父类,他只提供做作业的总步骤(DoMyHomeWork)模版方法,和下面的Write、Check、Submit都是抽象方法(纯虚函数),由子类自行实现。具体的子类ChineseHw和MathHw来实现做不同作业的差异步骤
- 调用函数时可以使用多态
- 父类属于抽象类,无法实例化对象
class Homework
{
public:void DoMyHomeWork() //做作业的整个步骤,但是做什么内容取决于子类{Write();Check();Submit();}virtual ~Homework(){}
public:virtual void Write() = 0; //写作业virtual void Check() = 0; //检查作业virtual void Submit() = 0; //提交作业
};class ChineseHw : public Homework
{
public:void Write() override{cout << "写语文作业" << endl;}void Check() override{cout << "检查语文作业" << endl;}void Submit() override{cout << "提交语文作业" << endl;}~ChineseHw(){cout << "析构语文作业对象" << endl;}
};class MathHw : public Homework
{
public:void Write() override{cout << "写数学作业" << endl;}void Check() override{cout << "检查数学作业" << endl;}void Submit() override{cout << "提交数学作业" << endl;}~MathHw() {cout << "析构数学作业对象" << endl;}
};int main()
{unique_ptr<Homework> h1(new ChineseHw);unique_ptr<Homework> h2(new MathHw);h1->DoMyHomeWork();h2->DoMyHomeWork();return 0;
}
7. 工厂模式
工厂类主要用于创建产品对象,对象的创建和使用分离,使得代码结构清晰。不需要了解产品的具体过程,只需要关系产品的使用
class Base
{
public:virtual void Print() = 0;virtual ~Base(){}
};class A : public Base
{
public:void Print() override{cout << "I am A" << endl;}~A() { cout << "~A" << endl; };
};
class B : public Base
{
public:void Print() override{cout << "I am B" << endl;}~B() { cout << "~B" << endl; };
};class Factory //工厂
{
public:static Base* CreateA() { return new A(); };static Base* CreateB() { return new B(); };
};
int main()
{Base* b1 = Factory::CreateA();Base* b2 = Factory::CreateB();b1->Print();b2->Print();delete b1;delete b2;return 0;
}
8. 观察者模式
观察者模式定义了对象之间一对多依赖关系,当一个被观察对象状态发生改变时,其他观察者对象会得到通知并自动更新
//==================== 观察者抽象类 ====================//
class Observer
{
public:virtual void update(const string& news) = 0;
};
//学生类
class Student : public Observer
{
private:string name;
public:Student(const string& n):name(n){}void update(const string& news){cout << "[Student: " << name << " ] get a news: " << news << endl;}
};
//老师类
class Teacher : public Observer
{
private:string name;
public:Teacher(const string& n) :name(n){}void update(const string& news){cout << "[Teacher: " << name << " ] get a news: " << news << endl;}
};
//==================== 被观察者抽象类 ====================//
class Subject
{
protected:vector<Observer*> _observers; //观察者的集合
public:virtual void attach(Observer* obs) //添加观察者{_observers.push_back(obs);}virtual void detach(Observer* obs) //删除观察者{for (int i = 0; i < _observers.size(); i++){if (obs == _observers[i]){_observers.erase(_observers.begin() + i);break;}}}virtual void notify(const string& news) = 0; //通知观察者
};
//学校机构类
class SchoolAgency : public Subject
{
public:void notify(const string& news) override{for (int i = 0; i < _observers.size(); i++){_observers[i]->update(news);}}
};
int main()
{SchoolAgency agency;Student st1("张三");Teacher tc1("李四");agency.attach(&st1);agency.attach(&tc1);agency.notify("今天天气小雨,建议带伞。");return 0;
}