According to the practice, we simply review the last problem. Last last time, "all these problems, will happen in combination? When the object array is initialized, if we want the initialization status of each object, how should it be?", About the combination I don't answer, I hope you have tested it. But the initialization of the object array is very interesting. Since it is necessary to initialize the default constructor, it is difficult to initialize each object. We have a idea that in this suitable constructor :), use the keyboard input to initialize each object. Then, the corresponding constructor of the two classes is changed to: // Constructor 1Shape :: Shape (void) {std :: cout << "/ ninput x, y (int):"; std :: cin >> x >> Y;} // Constructor 1Window :: Window: Shape () {std :: cout << "/ ninput width, height (int):"; std :: cin >> width >> Height; } This is not difficult to imagine the process of execution. However, there is a problem that if the size of the object array is relatively large, this type of input is more annoying :). Leave a question, can you find another high-efficiency initialization way, can meet our requirements here?
What we have to talk about today is that the initialization of special needs must be unique to examples with instance objects. The initialization work is the first step in our system starts, and our needs are all kinds. For example, sometimes, the instantiation requirements of the class can only have an object (note, not our programmer only instantiate an object, but the class mechanism allows you to instantiate an object!).
Such a problem, for beginners, often have such ideas: First, when instantified, the number of objects is counted, and the write control logic in the main function (or using the class) makes the object only one . Do not say that it can be achieved, this kind of thinking to external logic to complete the control is certainly inevitable. It is against the basic concept of OO! Second, more claims are implemented. On the implementation of the class, the object counter (integer static member variable) is defined, and then counts the count operation in the constructor. At the same time, it is judged that the counter value is greater than 1, then exit does not construct the object, so naturally, it will reach only the requirements that can only instantiate an object.
This kind of thinking is a bit mean. But how do you do it? Let's take a look. Our example is to ask the class library2,
Only one run instance can be run.
Try the definition of the class: #pragma ONCE
Class library2 {static int count; // Object counter Char book [20]; public: library2 (char _book []); Virtual ~ library2 (void); char * getBook (void); static int getCount (void);
}; # include "libray2.h" # using
INT library2 :: count = 0; // Initialization is 0
/ / Here is the key Library2 :: library2 (char _book []) {if (count == 0) {STRNCPY (Book, _book, sizeof (book)); count ;} else return; // (1) drop out? Return? Exit? Still? } Library2 :: ~ library2 (void) {count-;}
Char * library2 :: getbook (void) {return book;}
INT Library2 :: getCount (void) {Return Count;}
The key to the entire idea is to achieve the implementation of the code (1). The problem is, "If you exit, you don't construct the object, how can you do it? Let's take a look, can I do it? Change to "exit (0)"? If you can't get it, look back and look back, think about it :).
The answer is more obvious, "return" roles, no constructor does not do, the object is actually created, and the content is the value of the address. Just, count has no time to record. Use "exit (0)"? Exit the process, nor we want. You can test it, you will understand the role of the code.
Continue to take this idea, we have "exception mechanism" is not used. Since the class library2 can only have a running instance, when the programmer tries to build more than one object, we inform him that an exception happens: the number of objects you define more than our requirements. Due to the above code:
#pragma overceclass toomanyobj {}; // Exception class: Library2 object throws an exception Class library2 {static int count; char book [20]; public: library2 (char _book []); Virtual ~ library2 (Void) ); Char * getBook (void); static int getCount (Void);
}; // ... library2 :: library2 (char _book []) {if (count == 0) {STRNCPY (Book, _book, sizeof (book)); count ;} else throw new toomanyobj; // (1 ) Here use anomalous to control} // ...
Perhaps this is feasible, we hurry to test this version of class library2. The test file code is:
#include
void main () {try {char * name = "c primer"; library2 library (name); // First instantiation
Std :: cout << "Test: library's book: / n" << library.getbook () << "/ n";
Name = "Thinking In C "; Library2 Library2 (Name); // Second Instantiation: We are eager to have any effect here from abnormal // but the following logic part will affect? Std :: cout << "test: library2's book: / n" << library2.getbook () << "/ n"; std :: cout << "/ nlibrary2 HAS Object (Number):" << Library2 :: GetCount () << "./n";} catch (toomanyobj * e) // Processing exception {std :: cout << "/ nexception of direction}}}
Execute, the result is:
Test: Library's Book: C Primer
Exception of toomanyObj ... press any key to continue
Unfortunately, when an abnormality occurs, go directly to the abnormal processing section. We still have a lot of normal code, there is no chance to implement. "It exits the non-constructor", such a simple sentence, because it violates the initialization mechanism, but deliberately pursue it, how expensive. Moreover, we are always doing self-owners who are pinned from the individual logic controls, which should be avoided.
So what is the correct solution? The answer is that we need to use a mode Singleton. Please forgive me so much to write a post, because I think we encounter problems, always step by step approaching the answer - enough careful review of this process makes us more competing for new issues. Although the model itself is just a summary of experience, there is always its exploration process before experience.
We re-examine the problem, is "Requirement of instantiation can only have one", it is obvious that if the object can be created directly, if this: library2 library (name);
I think we have no chance to "exit the non-constructive object" if the program is not affected. So, here, we seem to be free! I want to think about our class, OO characteristics, is it difficult to lose the dark flower? Haha, then I put the constructor is also encapsulated into protection, and I don't let you create objects directly. Yes, this may be, I think again; since the constructor is encapsulated, then the object we have to generate, is definitely not this form:
Library2 Library (Name); What form is it? Only: library2 * plibrary; This is "inside", the focus is "middle" :), it should be a public member function to initialize the pointer (you think, this function call can only rely on class, it is static), Also guarantees whether you have a few pointers, they can only point to the address of the same object. How to do? Static variables and static functions have to be significant. Yes, we define a static pointer variable (pointing to class object) as a private member variable, then define a static member function, a common interface. If the static pointer variable is empty, initialize an object to it, return, otherwise, return it directly. This static member function is not the most exciting one as a solution? Realization code of this mode: #pragma overce
Class Library {private: static int count; // For verification with char book [20]; static library * _instance; // static pointer variable protected: library variable protected: library (void); // Constructor Virtual ~ Library (void); public : Static library * instance (void); // is the wonderful void setBook (char _book []); char * getBook (void); static int getcount (void);
#include "library.h" #using
INT Library :: count = 0; library * library :: _ instance = 0;
Library :: Library (void) {count ;}
Library :: ~ library (void) {count-; // delete _instance;
// Simple code, beautiful ideas, solve our problem library * library :: instance (void) {i (_instance == 0) {_instance = new library;} return _instance;
Void Library :: setBook (char _book []) {strncpy (book, _book, sizeof (book));}
Char * library :: getbook (void) {return book;}
INT Library :: getcount (void) {return count;}
The test code is likely to be:
// ... char * name = "C primer"; library * plibrary; plibrary = library :: instance (); // See the definition of the class: What happened here?
Plibrary-> SetBook (name);
Std :: cout << "TEST: Plibrary's book: / n" << plibrary-> getBook () << "/ n";
Library * plibrary2; plibrary2 = library :: instance (); // See the definition of the class: What happened here? Std :: cout << "TEST: PLIBRARY2's book: / n" << plibrary2-> getBook () < <"/ n"; std :: cout << "/ nlibrary has object (number):" << Library :: getcount () << "./n/n"; // ...
You look at this mode again, carefully ponder it. Oh, it turns out that we write the program, you can also have this! If you are interested in strict documents, and want to know more models, of course, I recommend you to see the "Four Gang" that is about the book :).
Overall, our initialization work is very worthy of attention. These four posts, struggled, mainly talking:
The first, good initialization process and the initialization of static members;
Second, some variables only have the only initialization form, through example, tell you to pay special attention. Then, step by step, look at the problem of shallow copies of resources.
The initialization problem in the third, combination and inheritance, and finally describe the places where the object array initialization needs to be paid. Mainly inherited. I want to clarify some ideas and emphasize some ideas.
Initialization of the fourth, special needs, to instance objects must be unique to an example.
These, but only the contest, but I hope to throw the jade, causing the thinking and concern. If you can help you, I will be very happy.
Finally, thank you for your attention.