When writing a library to export classes in C + +, we often just want to expose the interface and hide the implementation details of the class. This means that the header file we provide only provides declarations of public member functions to be exposed, and all other information in the class is not displayed in this header file. This is the time to use the technology of interface and implementation separation.
The following is a simple example to illustrate.
Class Clxexp is the class that we want to export, where a private member variable is an object of the Clxtest class, and the contents of each file are as follows:
lxTest.h file Contents:
Class Clxtest
{
Public
Clxtest ();
Virtual ~clxtest ();
void DoSomething ();
};
lxTest.cpp file Contents:
#include "LxTest.h"
#include <iostream>
using namespace Std;
Clxtest::clxtest ()
{
}
Clxtest::~clxtest ()
{
}
void Clxtest::D osomething ()
{
cout << "Do Something in class clxtest!" << Endl;
}
lxExp.h file Contents:
#include "LxTest.h"
Class Clxexp
{
Public
Clxexp ();
Virtual ~clxexp ();
void DoSomething ();
Private
Clxtest m_lxtest;
void Lxtest ();
};
lxExp.cpp file Contents:
#include "LxExp.h"
Clxexp::clxexp ()
{
}
Clxexp::~clxexp ()
{
}
In fact, this method is not necessary here, I just to illustrate the call relationship
void Clxexp::lxtest ()
{
M_lxtest.dosomething ();
}
void Clxexp::D osomething ()
{
Lxtest ();
}
In order for the user to be able to use our class Clxexp, we must provide the LxExp.h file so that the private members of the class Clxexp are exposed to the user. Furthermore, it is not enough to simply provide the LxExp.h file because the LxExp.h file includes the LxTest.h file, in which case we also provide the LxTest.h file. Then the implementation details of the Clxexp class are completely exposed to the user. In addition, when we make changes to the class clxtest (such as adding or removing some member variables or methods), we also need to update the LxTest.h file to the user, which is not related to the interface. If there are many objects like m_lxtest in the class clxexp, we will give the user n a header file like LxTest.h, and any of these classes have changes, we will update the header file to the user. Another point is that users must recompile in this case ! the above is a very small example, the time to recompile is negligible. However, if the class clxexp is heavily used by the user, then in a large project, we will have time to get a cup of coffee or something when we recompile. Of course, the above situation is not what we want to see! You can also imagine the user in their own program without changing the situation to keep updating the header files and compile, they will scold something in the heart. In fact, for users, they only care about the interface DoSomething () method of class Clxexp. So how can we only expose the dosomething () method of the class Clxexp without generating the above mentioned problems? The answer is-- the separation of the interface from the implementation . I can let the class Clxexp define the interface, and put the implementation in another class. Here are the specific methods:
First, add an implementation class clximplement to implement all the functions of clxexp. NOTE: Class clximplement has the same public member functions as the class CLXEXP because their interfaces are exactly the same.
lxImplement.h file Contents:
#include "LxTest.h"
Class Clximplement
{
Public
Clximplement ();
~clximplement ();
void DoSomething ();
Private
Clxtest m_lxtest;
void Lxtest ();
};
lxImplement.cpp file Contents:
#include "LxImplement.h"
Clximplement::clximplement ()
{
}
Clximplement::~clximplement ()
{
}
void Clximplement::lxtest ()
{
M_lxtest.dosomething ();
}
void Clximplement::D osomething ()
{
Lxtest ();
}
Then, modify the class Clxexp.
modified LxExp.h file contents:
Front-facing declaration
Class Clximplement;
Class Clxexp
{
Public
Clxexp ();
Virtual ~clxexp ();
void DoSomething ();
Private
Declares a pointer to a class clximplement and does not need to know the definition of a class clximplement
Clximplement *m_pimpl;
};
modified LxExp.cpp file contents:
#include "lxExp.h"This contains the definition header file for class Clximplement
#include "LxImplement.h"
Clxexp::clxexp ()
{
M_pimpl = new Clximplement;
}
Clxexp::~clxexp ()
{
if (M_pimpl)
DeleteM_pimpl;
}
void Clxexp::D osomething ()
{
M_pimpl->dosomething ();
}
The above method realizes the separation of the interface and implementation of the class Clxexp. Note the comments in the two files . The clxexp inside the class is just the interface, and the real implementation details are hidden inside the class clximplement. In order to be able to use class clximplement in class Clxexp and not include header file LxImplement.h, there must be a predecessor declaration class clximplement, and only pointers to class Clximplement objects can be used. Otherwise, it cannot be compiled. When publishing a library file, we simply provide the user with a header file LxExp.h, which does not expose any implementation details of the class Clxexp. And we do not have any changes to the class clxtest, no need to update the user header file (of course, the library file is to be updated, but in this case the user does not have to recompile !) ). One of the benefits of this is that the system analyst or senior programmer can define the interface of the class in the analysis phase, or even write the interface code (such as the modified LxExp.h file and the LxExp.cpp file above), and give the specific implementation of the class to other programmers.
=============================================================================================================== =======
In this February, I wrote an article on the technology of interface and implementation separation in C + +, using a very simple example to illustrate the benefits and implementations of interface and implementation separation in C + +. I am honored that this article was recommended to the homepage of Csdn and was reprinted by several websites.
However, when the article was written, it did not take into account the inheritance relationship between classes and classes. I will come to the specific discussion of this aspect.
This is illustrated by the example in the article mentioned above.
Execution class:
LxImplement.h File Contents:
#include "LxTest.h"
Class Clximplement
{
Public
Clximplement ();
~clximplement ();
void DoSomething ();
Private
Clxtest m_lxtest;
void Lxtest ();
};
LxImplement.cpp File Contents:
#include "LxImplement.h"
Clximplement::clximplement ()
{
}
Clximplement::~clximplement ()
{
}
void Clximplement::lxtest ()
{
M_lxtest.dosomething ();
}
void Clximplement::D osomething ()
{
Lxtest ();
}
Interface class:
LxExp.h File Contents:
Front-facing declaration
Class Clximplement;
Class Clxexp
{
Public
Clxexp ();
Virtual ~clxexp ();
void DoSomething ();
Private
Declares a pointer to a class clximplement and does not need to know the definition of a class clximplement
Clximplement *m_pimpl;
};
LxExp.cpp File Contents:
This contains the definition header file for class Clximplement
#include "LxImplement.h"
Clxexp::clxexp ()
{
M_pimpl = new Clximplement;
}
Clxexp::~clxexp ()
{
if (M_pimpl)
DeleteM_pimpl;
}
void Clxexp::D osomething ()
{
M_pimpl->dosomething ();
}
However, if the class Clxexp is a subclass of another class, and the method of the base class is called in the class Clxexp, the scheme above is not. For example, the base class for class Clxexp is the following:
Class Clxinf
{
Public
Clxinf ();
Virtual ~clxinf ();
BOOL Initset ();
virtual void dosomething ();
};
The declaration of the corresponding class Clxexp becomes the following form:
Class Clxexp:public Clxinf
{
Public
Clxexp ();
Virtual ~clxexp ();
void DoSomething ();
Private
Clximplement *m_pimpl;
};
Now, suppose we have to determine whether to perform an operation in the DoSomething () method of the class Clxexp, based on the return value of Initset (). The simplest way to implement this is to change the dosomething () method of the class Clxexp to look like this:
void Clxexp::D osomething ()
{
if (Initset ())
M_pimpl->dosomething ();
}
However, if this is the case, the interface and implementation are not completely separated , because the implementation details are exposed to the interface class . To avoid this, we have to put the method Initset () call to the base class Clxinf into the execution class clximplement. But how do you call the base class Clxinf of the interface class Clxexp in the execution class clximplement? In fact, it is very simple, because class Clxexp is a subclass of class Clxinf, then it inherits the method of class Clxinf, as long as the class clxexp the this pointer to class Clximplement, you can call the class Clxexp by this pointer method , of course, you can call the class Clxexp method inherited from the base class Clxinf. The following is the modified code:
LxImplement.h File Contents:
#include "LxTest.h"
header file containing the Declaration class Clxexp
#include "LxExp.h"
Class Clximplement
{
Public
constructor, a pointer to the clxexp of the class
Clximplement (Clxexp *plxexp);
~clximplement ();
void DoSomething ();
Private
Clxtest m_lxtest;
Defines a pointer to a class clxexp that can be called by the pointer to a method that inherits from the base class Clxexp
Clxexp *m_plxexp;
void Lxtest ();
};
LxImplement.cpp File Contents:
#include "LxImplement.h"
Clximplement::clximplement (Clxexp *plxexp)
{
M_plxexp = Plxexp;
}
Clximplement::~clximplement ()
{
}
void Clximplement::lxtest ()
{
M_lxtest.dosomething ();
}
void Clximplement::D osomething ()
{
if (M_plxexp->initset ())
Lxtest ();
}
For class Clxexp, just modify its constructor, and no other changes are necessary.
Clxexp::clxexp ()
{
M_pimpl = new Clximplement (this);
}
In this way, we have solved the problem mentioned earlier.
Of course, some might say that it's easier to let class clximplement inherit from class Clxinf. That way, you can call the method of the class Clxinf directly in the class clximplement, and you don't have to add any code. But we know that public inheritance is a is-a relationship between subclasses and base classes. That is, a subclass is a base class, just like a car. However, in our case, class clximplement is just an execution class of class clxexp, and it has nothing to do with the base class Clxinf of Class Clxexp, not to mention a clxinf. Therefore, class clximplement cannot be inherited from class Clxinf.
ref:http://blog.csdn.net/starlee/article/details/873489
Technology of interface and implementation separation in C + + ZZ