C++中hpp的适用

本文第一部分转载百度百科,在此感谢百度。第二部分示例为独立编写。

hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该hpp文件即可,无需再将cpp加入到project中进行编译。而现代码将直接编译到调用者的obj文件中,不再生成单独的obj,采用hpp将大幅度减少调用 project中的cpp文件数与编译次数,也不用再发布烦人的lib与dll,因此非常适合用来编写公用的开源库。

    hpp的优点不少,但是编写中有以下几点要注意:

1、是Header   Plus   Plus 的简写。

2、与*.h类似,hpp是C++程序头文件 。

3、VCL专用的头文件,已预编译。

4、是一般模板类的头文件。

5一般来说,*.h里面只有声明,没有实现,而*.hpp里声明实现都有,后者可以减少.cpp的数量。

6、*.h里面可以有using   namespace   std,而*.hpp里则无。

   
    7、不可包含全局对象和全局函数。
    由于hpp本质上是作为.h被调用者include,所以当hpp文件中存在全局对象或者全局函数,而该hpp被多个调用者include时,将在链接时导致符号重定义错误。要避免这种情况,需要去除全局对象,将全局函数封装为类的静态方法。
 
    8、类之间不可循环调用。
    在.h和.cpp的场景中,当两个类或者多个类之间有循环调用关系时,只要预先在头文件做被调用类的声明即可,如下:
    class B;
    class A{
    public:
         void someMethod(B b);
    };
    class B{
    public :
         void someMethod(A a);
    };
    在hpp场景中,由于定义与实现都已经存在于一个文件,调用者必需明确知道被调用者的所有定义,而不能等到cpp中去编译。因此hpp中必须整理类之间调用关系,不可产生循环调用。同理,对于当两个类A和B分别定义在各自的hpp文件中,形如以下的循环调用也将导致编译错误:
    //a.hpp
    #include "b.hpp"
    class A{
    public :
        void someMethod(B b);
    };
 
    //b.hpp
    #include "a.hpp"
    class B{
    public :
        void someMethod(A a);
    };
 
    9、不可使用静态成员。
    静态成员的使用限制在于如果类含有静态成员,则在hpp中必需加入静态成员初始化代码,当该hpp被多个文档include时,将产生符号重定义错误。唯一的例外是const static整型成员,因为在vs2003中,该类型允许在定义时初始化,如:
    class A{
    public:
       const static int intValue = 123;
    };
    由于静态成员的使用是很常见的场景,无法强制清除,因此可以考虑以下几种方式(以下示例均为同一类中方法)
    1.类中仅有一个静态成员时,且仅有一个调用者时,可以通过局域静态变量模拟
    //方法模拟获取静态成员
    someType getMember()
    {
       static someType value(xxx);//作用域内静态变量
       return value;
    }
    2.类中有多个方法需要调用静态成员,而且可能存在多个静态成员时,可以将每个静态成员封装一个模拟方法,供其他方法调用。
 
    someType getMemberA()
    {
       static someType value(xxx);//作用域内静态变量
       return value;
    }
    someType getMemberB()
    {
       static someType value(xxx);//作用域内静态变量
       return value;
    }
   void accessMemberA()
    {
       someType member = getMemberA();//获取静态成员
    };
    //获取两个静态成员
    void accessStaticMember()
    {
       someType a  = getMemberA();//获取静态成员
       someType b = getMemberB();
    };
 
    3.第二种方法对于大部分情况是通用的,但是当所需的静态成员过多时,编写封装方法的工作量将非常巨大,在此种情况下,建议使用Singleton模式,将被调用类定义成普通类,然后使用Singleton将其变为全局唯一的对象进行调用。
    如原h+cpp下的定义如下:
    class A{
    public :
        type getMember(){
           return member;
        }
        static type member;//静态成员
    }
 
    采用singleton方式,实现代码可能如下(singleton实现请自行查阅相关文档)
    //实际实现类
    class Aprovider{
    public :
        type getMember(){
           return member;
        }
        type member;//变为普通成员
    }
 
    //提供给调用者的接口类
    class A{
    public :
        type getMember(){
           return Singleton<AProvider >::getInstance()->getMember();
        }
    }
 
目前,模板的声明与定义需要在同一个文件中。如果分开,g++编译链接会报错。即使有一定的方法去模板的声明与定义分开,但是鉴于编译器的支持,不建议这么做。而hpp正好提供了这样的适用性,所以,无论是类模板还是函数模板,都在*.hpp文件中。在此,给个Demo,方便大家学习。
 
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <string>
 5 #include <typeinfo>
 6 #include "adapter.hpp"
 7 using namespace std;
 8 
 9 struct Base {}; // non-polymorphic
10 struct Derived : Base {};
11 
12 struct Base2 { virtual void foo() {} }; // polymorphic
13 struct Derived2 : Base2 {};
14 
15 int main() {
16     Test ttdata;
17     ttdata.data = 2;
18     Test ttdata2;
19     ttdata2.data = 5;
20     TestCom::compare<struct Test>(ttdata, ttdata2);
21 
22     A a;
23     Test2 tt;
24     a.foo<Test2>(tt);
25     Test tst1;
26     Test2 tst2;
27     a.foo<Test,Test2>(tst1, tst2);
28     int myint = 50;
29     //int intx = 100;
30     if(typeid(myint).name() == typeid(int).name())
31         cout << "same:" << typeid(myint).name() << endl;
32     std::string mystr = "string";
33     double *mydoubleptr = NULL;
34 
35     std::cout << "myint has type: " << typeid(myint).name() << '
'
36               << "mystr has type: " << typeid(mystr).name() << '
'
37               << "mydoubleptr has type: " << typeid(mydoubleptr).name() << '
';
38 
39     // std::cout << myint is a glvalue expression of polymorphic type; it is evaluated
40     const std::type_info& r1 = typeid(std::cout << myint);
41     std::cout << '
' << "std::cout<<myint has type : " << r1.name() << '
';
42 
43     // std::printf() is not a glvalue expression of polymorphic type; NOT evaluated
44     const std::type_info& r2 = typeid(printf("%d
", myint));
45     std::cout << "printf("%d\n",myint) has type : " << r2.name() << '
';
46 
47     // Non-polymorphic lvalue is a static type
48     Derived d1;
49     Base& b1 = d1;
50     std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '
';
51 
52     Derived2 d2;
53     Base2& b2 = d2;
54     std::cout << "reference to polymorphic base: " << typeid(b2).name() << '
';
55 
56     try {
57         // dereferencing a null pointer: okay for a non-polymorphic expression
58         std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '
';
59         // dereferencing a null pointer: not okay for a polymorphic lvalue
60         Derived2* bad_ptr = NULL;
61         std::cout << "bad_ptr points to... ";
62         std::cout << typeid(*bad_ptr).name() << '
';
63     } catch (const std::bad_typeid& e) {
64         std::cout << " caught " << e.what() << '
';
65     }
66 }
main.cpp
 
 1 #include "solution.h"
 2 
 3 class TestCom{
 4 public:
 5     template<typename T>
 6     static void compare(const T& v1, const T& v2);
 7 };
 8 
 9 template<typename T>
10 void TestCom::compare(const T& v1, const T& v2)
11 {
12     if(typeid(T) == typeid(struct Test))
13     {
14         if(v1.data < v2.data)
15             cout << v1.data << " " << v2.data<< " v1 < v2" << endl;
16         if(v1.data > v2.data)
17             cout << v1.data << " " << v2.data<< " v1 > v2" << endl;
18     }else{
19         printf("T is not Test : %s
", typeid(Test2).name());
20     }
21 }
22 
23 //struct A{
24 //    void func();
25 //    template < typename T1 > void foo(T1 param);
26 //};
27 
28 struct A
29 {
30     void func(){cout << "func()" << endl;}
31     template < typename T1 > void foo(T1 param) {
32         //if(typeid(Test2).name() == typeid(param).name()){
33         if(typeid(Test2) == typeid(T1)){
34             param.data = 100;
35             string str("Test2 copy");
36             strncpy(param.buf, str.c_str(), str.size());
37             cout << "int:" << param.data << " " << param.buf <<  " type:" << typeid(param).name()<<  endl;
38         }else{
39             printf("err, though equal,but not reg, %s
", typeid(T1).name());
40         }
41     }
42 
43     template < typename T1, typename T2 > void foo(T1 param, T2 param2) {
44         //if(typeid(Test2).name() == typeid(param).name()){
45         if(typeid(T2) == typeid(T1)){
46             param.data = 50;
47             param2.data = 100;
48             printf("param:%d, param2:%d
", param.data, param2.data);
49         }else if ( typeid(Test2) == typeid(param2)) {
50             param2.data = 100;
51             string str("Test2 copy");
52             strncpy(param2.buf, str.c_str(), str.size());
53             cout << "int:" << param2.data << " " << param2.buf <<  " type:" << typeid(param2).name()<<  endl;
54         } else{
55             printf("err, though equal,but not reg, %s
", typeid(T1).name());
56         }
57     }
58 };
AdapterEx.hpp
 1 #ifndef _PROXY_H_
 2 #define _PROXY_H_
 3 #include <string>
 4 #include <string.h>
 5 using namespace std;
 6 
 7 struct Test{
 8     int data;
 9     //string str;
10     float f;
11 };
12 
13 struct Test2{
14     int data;
15     //string str;
16     char buf[64];
17     Test2(){
18         data = 0;
19         memset(buf, 0x00, sizeof(buf));
20     }
21 };
22 
23 #endif
solution.h
原文地址:https://www.cnblogs.com/guxuanqing/p/4805144.html