C + + Primer Learning Notes _24_ class and Data Abstraction (--static) with singleton mode, auto_ptr and singleton mode, const member function, const object, mutable modifier
Objective
"Example" writes out the five basic principles of object-oriented?
Solution: Single Duty principle, open closure principle, dependency inversion principle, interface isolation principle and Richter replacement principle
Richter substitution principle: subtypes must be able to replace their base types.
There are three types of design patterns: Creation, structural, and behavioral patterns
First, static and single-case mode
1. Single Case mode
The intent of the singleton pattern:ensure that a class has only one instance and provides a global access point to access it。
(1) The first form of
#include <iostream> #include <string>using namespace Std;class singleton{private: static Singleton S; int i; Singleton (int x): I (x) {cout << "Singleton" << Endl;} Singleton & operator = (singleton&); Assignment Singleton (const singleton&) is not allowed, copy public is not allowed: static singleton& instance () {return s;} int GetValue () {return i;} void SetValue (int x) {i = x;}}; Singleton Singleton::s (47); Defines a static member Sint main () { singleton& s = singleton::instance (); cout << s.getvalue () << Endl; singleton& s2 = singleton::instance (); S2.setvalue (9); cout << s.getvalue () << Endl; return 0;}
Operation Result:
Singleton
47
9
The above implementation implements a single-column pattern by returning a reference. If a pointer is returned instead of a reference, the user may accidentally delete the pointer, so the above implementation is more secure than the return pointer.
(2) The second form of
#include <iostream> #include <string>using namespace Std;class singleton{private: int i; Singleton (int x): I (x) {cout << "Singleton" << Endl;} void operator= (singleton&); Singleton (const singleton&); Copy public is not allowed: static singleton& instance () { static Singleton s (); return s; } int GetValue () {return i;} void SetValue (int x) {i = x;}}; int main () { singleton& s = singleton::instance (); cout << s.getvalue () << Endl; singleton& s2 = singleton::instance (); S2.setvalue (9); cout << s.getvalue () << Endl; return 0;}
Operation Result:
Singleton
47
9
The above method implements a singleton pattern by creating a static object inside the member function.
Note that the above two methods do not consider the problem of thread safety, such as to be applied in multi-threaded environment, need to lock.
"Example: Prohibit copy, assign, default constructor create object action"
#include <iostream>using namespace Std;class singleton{public: static Singleton *getinstance () { if (Instance_ = = NULL) { instance_ = new Singleton; } return instance_; } ~singleton () { cout << "~singleton ..." << Endl; } Private: Singleton (const Singleton &other); Place copy function in private, prohibit copy Singleton &operator= (const Singleton &other); Prohibit assignment Singleton () //Disallow creation of object { cout << "Singleton ..." << Endl; } Static Singleton *instance_;}; Singleton *singleton::instance_;int Main (void) { //singleton s1; Error, calling the default constructor Singleton *s1 = Singleton::getinstance (); Singleton *s2 = Singleton::getinstance (); Singleton S3 (*S1); Error, call copy constructor return 0;}
Operation Result:Singleton ...
Although the above program calls two getinstance functions, it only calls the constructor once, that is, an object is created. Declare the assignment operator and copy constructor as private and prohibit copying . But one problem with the program is that the object's lifetime is not destroyed .
2, in order to solve the problem of the object will not be destroyed, you can use a static nested class object to solve:
#include <iostream>using namespace Std;class singleton{public:static Singleton *getinstance () {if (in Stance_ = = NULL) {instance_ = new Singleton; } return Instance_; } ~singleton () {cout << "~singleton ..." << Endl; } class Garbo {public: ~garbo () {if (Singleton::instance_! = NULL) { Delete Instance_; }}};p Rivate:singleton (const Singleton &other); Place copy function in private, prohibit copy Singleton &operator= (const Singleton &other); Prohibit Assignment Singleton ()//Disallow creation of object {cout << "Singleton ..." << Endl; } static singleton* Instance_; Static Garbo Garbo_; Using deterministic destruction of objects}; Singleton::garbo Singleton::garbo_; singleton* Singleton::instance_;int Main (void) {//singleton S1; Error, calling the default constructor Singleton *s1 = Singleton::getinstance (); Singleton *s2 = Singleton::getinstance (); Singleton S3 (*S1); Error, call copy constructor return 0;}
Operation Result:Singleton ...
~singleton ...
Explanation: The deterministic destructor of a statically nested object invokes the destructor of the Garbo class and deletes a pointer to the Singleton class within the destructor.
3, the above method is more cumbersome, you can also return the local static object reference to solve:
#include <iostream>using namespace Std;class singleton{public: static singleton& getinstance () { static Singleton instance; Local static object return instance; } ~singleton () { cout << "~singleton ..." << Endl; } Private: Singleton (const Singleton &other); Place copy function in private, prohibit copy Singleton &operator= (const Singleton &other); Prohibit assignment Singleton () //Disallow creation of object { cout << "Singleton ..." << Endl; }}; int main (void) { singleton& S1 = singleton::getinstance (); singleton& s2 = singleton::getinstance (); return 0;}
Running Result: Singleton ...
~singleton ...
Explanation: A local static object is initialized only once, so calling multiple getinstance functions gets the same object. because a static object is used within a function, it is not thread-safe.
4, can actually use the AUTO_PTR smart pointer to solve, the program is as follows, more detailed on the auto_ptr will be discussed in the following.
#include <iostream> #include <memory>using namespace Std;class singleton{public: Static Singleton * getinstance () { if (instance_.get () = = NULL) { Instance_ = auto_ptr<singleton> (new Singleton); } return Instance_.get (); } ~singleton () { cout << "~singleton ..." << Endl; } Private: Singleton (const Singleton &other); Singleton &operator= (const Singleton &other); Singleton () { cout << "Singleton ..." << Endl; } Static auto_ptr<singleton> Instance_;}; auto_ptr<singleton> Singleton::instance_;int Main (void) { Singleton *s1 = Singleton::getinstance (); Singleton *s2 = Singleton::getinstance (); return 0;}
Operation Result:
Singleton ...
~singleton ...
5, a hungry man type singleton mode (initialization is done at class load, so class load is slow, but object gets faster)
In fact, all of the singleton pattern examples above are not thread-safe, assuming that if two threads run to the statement if (instance = = null)at the same time, the instance does not create , then two threads will create an instance. If you do not want the lock to be thread safe, you can use the A Hungry man mode (that is, before the main function as an instance):
#include <iostream>using namespace Std;class singleton{public:static const singleton* getinstance () { return instance_; } ~singleton () {cout << "~singleton ..." << Endl; } class Garbo {public: ~garbo () {if (Singleton::instance_! = NULL) { Delete Instance_; }}};p Rivate:singleton (const Singleton &other); Place copy function in private, prohibit copy Singleton &operator= (const Singleton &other); Prohibit Assignment Singleton ()//Disallow creation of object {cout << "Singleton ..." << Endl; } static const singleton* Instance_; Static Garbo Garbo_; Using deterministic destructor of object};const singleton* singleton::instance_ = new Singleton (); Singleton::garbo Singleton::garbo_;int Main (void) {//singleton S1; Error, calling the default constructor const Singleton *S1 = Singleton::getinstance (); Const Singleton *S2 = Singleton::getinstance (); Singleton S3 (*S1); Error, call copy constructor return 0;}
Operation Result:
Singleton ...
~singleton ...
6, or through the lock way to achieve, detailed will be discussed in the following.
Second, const member function, const object, mutable modifier
1. CONST member function
The const member function does not modify the state of an object
The const member function can only access the value of a data member and cannot modify it
2. Const Object
If you designate an object as const, tell the compiler not to modify it
Definition of a Const object:
Const Class Name Object name (parameter table);
Const object cannot call non-const member function
3, mutable decoration
Data members decorated with mutable can be modified even if they are in a const object or in a const member function.
#include <iostream>using namespace Std;class test{public: Test (int x): X_ (x), Outputtimes_ (0) {} int GetX () const { cout << "Const GetX ..." << Endl; X_ = +; Error, attempting to modify data member return x_; } int GetX () { cout << "GetX ..." << Endl; return x_; } void Output () const { cout << "x=" << x_ << Endl; outputtimes_++; } int getoutputtimes () const { return outputtimes_; } Private: int x_; mutable int outputtimes_; mutable modifier};int Main (void) { const Test T (ten); T.getx (); Test T2 (+); T2. GetX (); T.output (); T.output (); cout << t.getoutputtimes () << Endl; return 0;}
Operation Result:
Const GetX ...
GetX ...
x=10
x=10
2
Reference:
C + + Primer Fourth Edition
Effective C + + 3rd
http://blog.csdn.net/jnu_simba/article/details/9282235
http://blog.csdn.net/zjf280441589/article/details/24704603
C + + Programming specification
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
C + + Primer Learning Notes _24_ class and Data Abstraction (--static) with singleton mode, auto_ptr and singleton mode, const member function, const object, mutable modifier