Design Mechanism of C ++ program 1: NVI Mechanism

Source: Internet
Author: User
Tags addall

In the C ++ program design, there are some typical design and development mechanisms that need to be discussed in detail. Here, we will give you a lot of advice to help you build your own skills.

1. Introduction

In the standard C ++ library, we can see this phenomenon:

Six public virtual functions, all of which are std: exception: what () and their overloading.

142 non-public virtual functions.

What is the purpose of this design? Why do I set the virtual function as non-public?

This is what the NVI mechanism requires: declare virtual functions as non-public functions, and declare public functions as non-virtual functions-select either virtual function or public function.

2. Mechanism Analysis

Programmers often use the virtual functions in the base class to provide an interface definition (virtual credit) and provide its implementation (a specific implementation ).

1: class Base {
2: public:
3: virtual void Foo (int ){
4: cout <"Bases Foo! "<Endl;
5 :};
6:}; the problem lies in "at the same time"-a form that defines the interface and a default implementation. Obviously, this design does not split the interface definition and implementation. At this time, we can use the idea of the template method mode:

1: class Base {
2: public:
3: void Foo (){
4: DoFoo1 ();
5: DoFoo2 ();
6:} // use DoFooX ()
7: private:
8: virtual void DoFoo1 (){
9: cout <"Bases DoFoo1" <endl;
10 :}
11: virtual void DoFoo2 (){
12: cout <"Bases DoFoo2" <endl;
13 :}
14 :};
15:
16: class Derived: public Base {
17: private:
18: virtual void DoFoo1 (){
19: cout <"Deriveds DoFoo1" <endl;
20 :};
21 :}; the function Foo defines the interface form, while the DoFooX () function customizes the behavior of the Foo function and achieves the separation of interface definition and implementation, here is an example to illustrate the benefits: if we want to implement lock unlocking control for the CS (Critical Section) in Foo:

If we complete this interface and implement separation, we can add the required process at the base class interface, and the subclass does not need to be modified:

1: class Base {
2: public:
3: void Foo (){
4: cout <"Locking" <endl;
5: DoFoo1 ();
6: DoFoo2 ();
7: cout <"Unlocking" <endl;
8:} // use DoFooX ()
9: private:
10: virtual void DoFoo1 (){
11: cout <"Bases DoFoo1" <endl;
12 :}
13: virtual void DoFoo2 (){
14: cout <"Bases DoFoo2" <endl;
15 :}
16:
17 :};
18:
19: class Derived: public Base {
20: private:
21: virtual void DoFoo1 (){
22: cout <"Deriveds DoFoo1" <endl;
23 :};
24:}; if the interface and implementation separation are not implemented, You need to modify from the base class to the subclass:

1: class Base {
2: public:
3: virtual void Foo (){
4: cout <"Locking" <endl;
5: cout <"Bases Foo" <endl;
6: cout <"Unlocking" <endl;
7 :}
8 :};
9:
10: class Derived: public Base {
11: public:
12: virtual void Foo (){
13: cout <"Locking" <endl;
14: cout <"Deriveds Foo" <endl;
15: cout <"Unlocking" <endl;
16 :};
17:}; note that the virtual function is set to protected only when the subclass needs to call the virtual function of the base class (otherwise there is no permission), and The NVI mechanism is not applicable to the destructor, for destructor, if it is set to public, it should be set to virtual (in the base class that allows deletion of polymorphism ), otherwise, it is set to private or protected in a non-virtual form (excluding the base class of the polymorphism deletion ).

Risks:

The first is the FBC problem (Fragile Base Class). Below is an example:

1: class Set {
2: std: set <int> s _;
3: public:
4: void add (int I ){
5: s _. insert (I );
6: add_impl (I); // Note virtual call.
7 :}
8: void addAll (int * begin, int * end ){
9: s _. insert (begin, end); // --------- (1)
10: addAll_impl (begin, end); // Note virtual call.
11 :}
12: private:
13: virtual void add_impl (int I) = 0;
14: virtual void addAll_impl (int * begin, int * end) = 0;
15 :};
16: class CountingSet: public Set {
17: private:
18: int count _;
19: virtual void add_impl (int I ){
20: count _ ++;
21 :}
22: virtual void addAll_impl (int * begin, int * end ){
23: count _ + = std: distance (begin, end );
24 :}
25 :}; if we modify the addAll function in the parent class and call the add function again for the numbers from begin to end, the sub-class function is disordered-the sub-class count will double the number of records (because in the sub-class, add_impl will count one at a time, and addAll_impl will count the whole one at a time ). Therefore, to prevent FBC, a public non-virtual function calls a private virtual function.

Second, performance considerations. After all, there is an additional layer of function calls. In this regard, reference 2 states: "a word about efficiency: No, none is lost in practice because if the public function is a one-line passthrough declared inline, all compilers I know of will optimize it away entirely, leaving no overhead. (Indeed, some compilers will always make such a function inline and eliminate it, whether you personally really wanted it to or not, but that's another story .)"

3. Summary

Put the NVI mechanism in your mind. If you still don't understand it, a story may be more suitable for you.

1. Objective C ++ Item 35 Consider Alternatives To Virtual Functions

2. http://www.gotw.ca/publications/mill18.htm

3. http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.3

4. http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.4

5. http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.