阻止类创建实例的方法有两种:
一种就是我们所熟知的抽象类,另一种是工作中较为常用的设计模式:单例模式。
首先我们先疏通一下什么是抽象类和接口:
拥有一个或多个纯虚函数的类叫做抽象类,纯虚函数又是基于虚函数上函数体为0的函数(为0就是没有函数实现,仅仅是一个函数声明),这些若干纯虚函数构成派生类必须去实现的接口。
如果抽象类的派生类不去实现接口的具体实现,那么派生类也是抽象类,也不能创建实例。
接口:指函数的集合,定义了一个类或多个类(指派生类)的具体实现。
有时,把只有纯虚函数而没有其他数据成员的类称之为接口类。
抽象类无法创建实例的情况:
重写纯虚函数即可创建实例,但不是基类的实例。
#include<iostream>
using namespace std;
class A {
virtual void func() = 0; //抽象类
};
class B : public A {
public:
void func() { //函数重写
cout << "重写纯虚函数";
}
};
int main() {
B b;
b.func();//如果B类中不重写A类中的纯虚函数,那么B类也是抽象类,无法创建实例
return 0;
}
输出:
重写纯虚函数
设计模式:单例模式
条件:
构造函数私有化
拷贝构造函数delete
赋值运算符重载也delete
创建全局节点:静态成员函数,返回值为引用(因为拷贝构造和赋值运算符已经被删除)
#include<iostream>
using namespace std;
class A {
public:
static A& getInstance(int a) { //全局访问节点(静态)
static A instance(a);//局部对象,初始化一次,C++11之后static修饰的变量都是线程安全的
return instance;
}
private:
int a;
A(int a) { //构造函数私有化
this->a = a;
cout << a;
}
A(const A& other) = delete;//删除拷贝构造函数
A& operator=(const A& other) = delete;//删除运算符重载函数
};
int main() {
A::getInstance(2); //通过全局访问节点来创建对象,这里又是有参构造函数,传了2
return 0;
}
输出:
2
#include<iostream>
using namespace std;
class A {
int age;
string name;
//构造函数私有化
A(int age,string name) {
this->age = age;
this->name = name;
}
//拷贝构造删除
A(const A& other) = delete;
//赋值运算符重载删除
A& operator=(const A&) = delete;
public:
//通过静态成员函数创建对象(有参、无参)
static A& getInstance(int age,string name) {
//静态局部对象:只创建一次对象,因为静态局部变量只被初始化一次
//在C++11后线程安全,不必考虑线程同步
static A instance(age,name);
return instance;
}
void show() {
cout <<"年龄:" << age << " " <<"姓名:" << name << endl;
}
};
int main() {
A::getInstance(18,"张三").show();
A::getInstance(17, "法外狂徒").show();//只能创建出一次对象,此条不输出
return 0;
}