• 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
  • 相关阅读:
    深入理解泛型之JAVA泛型的继承和实现、泛型擦除
    hadoop过程中遇到的错误与解决方法
    微服务拆分到什么粒度合适——康威定律
    墨菲定律(设计系统)和康威定律(系统划分)
    Hadoop-Impala学习笔记之SQL参考
    Hadoop-Impala学习笔记之管理
    Hadoop2-HDFS学习笔记之入门(不含YARN及MR的调度功能)
    Hadoop-Impala学习笔记之入门
    解决 Invalid character found in method name. HTTP method names must be tokens 异常信息
    从康威定律和技术债看研发之痛
  • 原文地址:https://www.cnblogs.com/guxuanqing/p/4805144.html
Copyright © 2020-2023  润新知