在之前的文章[C++的单例模式为什么不直接全部使用static,而是非要实例化一个对象?] 发布以后,陆陆续续收到很多网友留言提问,问题主要集中在文中的这一段:
class Singleton {
public:
static void on() {Singleton::isOn = true;}
static void off() {Singleton::isOn = false;}
static bool state() {return Singleton::isOn;}
private:
static bool isOn;
};
class Monitor: public Singleton {
public:
static void addBrightness(int val) { brightness += val;}
static void subBrightness(int val) { brightness -= val;}
static int getBrightness() { return brightness;}
private:
static int brightness;
};
如果有子类继承这一父类,来拓展成新的子类,比如Monitor显示器类有开关状态,同时扩展了一个亮度的成员。但是父子类的static成员变量是共享的,其isOn成员会有问题。
大家纷纷留言评论:“其isOn成员会有问题”,是指什么问题?会有什么问题?
甚至有很多网友是从其他公众号看到了我这篇文章,然后特地赶过来追问的。比如:
这位网友你是有多不想关注我……
好了,我来解释一下。这上面的例子中isOn是父类Singleton中的静态成员,子类Monitor继承了父类后,isOn也还是同一个。如果这时候父类所代表的单例调用了on函数将isOn改为true。那么子类Monitor的isOn也会被修改,因为它们真的是同一个变量!不信你看:
#include <iostream>
using namespace std;
class Singleton {
public:
static void on() {Singleton::isOn = true;}
static void off() {Singleton::isOn = false;}
static bool state() {return Singleton::isOn;}
private:
static bool isOn;
};
bool Singleton::isOn = true;
class Monitor: public Singleton {
public:
static void addBrightness(int val) { brightness += val;}
static void subBrightness(int val) { brightness -= val;}
static int getBrightness() { return brightness;}
private:
static int brightness;
};
int Monitor::brightness = 0;
int main() {
Singleton::on();
Monitor::on();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
Singleton::off();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
}
输出:
Singleton state:1 Monitor state:1
Singleton state:0 Monitor state:0
但逻辑上两个类应该表示不同资源的“单例”,不应该互相影响才对。所以我说的有问题,不是说编译会有问题,而是说使用起来在逻辑上会有问题。有一种解法是你可以在子类里面再重新定义一个static的isOn变量及其相关的读写函数。这样父子类就解耦了。但是如果你要这样改的话,那么使用继承还有什么意义呢?完全没必要继承了啊。
好了,继续看。
有的少年可能在此时会想起来,我上篇文章是在介绍Meyers' Singleton
。于是想把isOn改成局部静态变量。那么这样是否就没问题呢?
#include <iostream>
using namespace std;
class Singleton {
public:
static bool& getOn() {
static bool isOn = true;
return isOn;
}
static void on() {getOn() = true;}
static void off() {getOn() = false;}
static bool state() {return getOn();}
};
class Monitor: public Singleton {
public:
static int& Brightness() {
static int brightness = 0;
return brightness;
}
static void addBrightness(int val) { Brightness() += val;}
static void subBrightness(int val) { Brightness() -= val;}
static int getBrightness() { return Brightness();}
};
int main() {
Singleton::on();
Monitor::on();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
Singleton::off();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
}
同样有问题,虽然是局部静态变量了。但这种写法父子类使用的依旧是同一个isOn的静态变量!编译运行,输出还是:
Singleton state:1 Monitor state:1
Singleton state:0 Monitor state:0
请注意并不是说使用了静态局部变量就是Meyers' Singleton
。于是手快的少年,肯定立马写出了下一个版本:
#include <iostream>
using namespace std;
class Singleton {
public:
static Singleton& getInstance() {
static Singleton inst;
return inst;
}
static void on() {getInstance().isOn = true;}
static void off() {getInstance().isOn = false;}
static bool state() {return getInstance().isOn;}
protected:
bool isOn = true;
};
class Monitor: public Singleton {
public:
static Monitor& getInstance() {
static Monitor inst;
return inst;
}
static void addBrightness(int val) { getInstance().brightness += val;}
static void subBrightness(int val) { getInstance().brightness -= val;}
static int getBrightness() { return getInstance().brightness;}
private:
int brightness = 0;
};
int main() {
Singleton::on();
Monitor::on();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
Singleton::off();
cout<<"Singleton state:" << Singleton::state()
<< " Monitor state:" << Monitor::state()<<endl;
}
少年你接近了真相,但是还是不对。这也不是Meyers' Singleton
。输出还是:
Singleton state:1 Monitor state:1
Singleton state:0 Monitor state:0
少年:“我悟了”
#include <iostream>
using namespace std;
class Singleton {
public:
static Singleton& getInstance() {
static Singleton inst;
return inst;
}
void on() {isOn = true;}
void off() {isOn = false;}
bool state() {return isOn;}
protected:
bool isOn = true;
};
class Monitor: public Singleton {
public:
static Monitor& getInstance() {
static Monitor inst;
return inst;
}
void addBrightness(int val) { brightness += val;}
void subBrightness(int val) { brightness -= val;}
int getBrightness() { return brightness;}
private:
int brightness = 0;
};
int main() {
Singleton::getInstance().on();
Monitor::getInstance().on();
cout<<"Singleton state:" << Singleton::getInstance().state()
<< " Monitor state:" << Monitor::getInstance().state()<<endl;
Singleton::getInstance().off();
cout<<"Singleton state:" << Singleton::getInstance().state()
<< " Monitor state:" << Monitor::getInstance().state()<<endl;
}
再次编译运行之后,输出:
Singleton state:1 Monitor state:1
Singleton state:0 Monitor state:1
没错这才是正确写法,要注意Meyers' Singleton
,除了局部静态变量、数据成员是非静态这些条件以外,如果你要读写其中的数据成员,一定要像普通类一样写普通成员函数,而非静态成员函数来操作。如果你不希望写这些成员函数,那你就直接把单例中的数据成员声明成public吧……
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8