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

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,方便大家学习。
 
 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <typeinfo>
#include "adapter.hpp"
using namespace std; struct Base {}; // non-polymorphic
struct Derived : Base {}; struct Base2 { virtual void foo() {} }; // polymorphic
struct Derived2 : Base2 {}; int main() {
Test ttdata;
ttdata.data = ;
Test ttdata2;
ttdata2.data = ;
TestCom::compare<struct Test>(ttdata, ttdata2); A a;
Test2 tt;
a.foo<Test2>(tt);
Test tst1;
Test2 tst2;
a.foo<Test,Test2>(tst1, tst2);
int myint = ;
//int intx = 100;
if(typeid(myint).name() == typeid(int).name())
cout << "same:" << typeid(myint).name() << endl;
std::string mystr = "string";
double *mydoubleptr = NULL; std::cout << "myint has type: " << typeid(myint).name() << '\n'
<< "mystr has type: " << typeid(mystr).name() << '\n'
<< "mydoubleptr has type: " << typeid(mydoubleptr).name() << '\n'; // std::cout << myint is a glvalue expression of polymorphic type; it is evaluated
const std::type_info& r1 = typeid(std::cout << myint);
std::cout << '\n' << "std::cout<<myint has type : " << r1.name() << '\n'; // std::printf() is not a glvalue expression of polymorphic type; NOT evaluated
const std::type_info& r2 = typeid(printf("%d\n", myint));
std::cout << "printf(\"%d\\n\",myint) has type : " << r2.name() << '\n'; // Non-polymorphic lvalue is a static type
Derived d1;
Base& b1 = d1;
std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n'; Derived2 d2;
Base2& b2 = d2;
std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n'; try {
// dereferencing a null pointer: okay for a non-polymorphic expression
std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '\n';
// dereferencing a null pointer: not okay for a polymorphic lvalue
Derived2* bad_ptr = NULL;
std::cout << "bad_ptr points to... ";
std::cout << typeid(*bad_ptr).name() << '\n';
} catch (const std::bad_typeid& e) {
std::cout << " caught " << e.what() << '\n';
}
}

main.cpp

 
 #include "solution.h"

 class TestCom{
public:
template<typename T>
static void compare(const T& v1, const T& v2);
}; template<typename T>
void TestCom::compare(const T& v1, const T& v2)
{
if(typeid(T) == typeid(struct Test))
{
if(v1.data < v2.data)
cout << v1.data << " " << v2.data<< " v1 < v2" << endl;
if(v1.data > v2.data)
cout << v1.data << " " << v2.data<< " v1 > v2" << endl;
}else{
printf("T is not Test : %s\n", typeid(Test2).name());
}
} //struct A{
// void func();
// template < typename T1 > void foo(T1 param);
//}; struct A
{
void func(){cout << "func()" << endl;}
template < typename T1 > void foo(T1 param) {
//if(typeid(Test2).name() == typeid(param).name()){
if(typeid(Test2) == typeid(T1)){
param.data = ;
string str("Test2 copy");
strncpy(param.buf, str.c_str(), str.size());
cout << "int:" << param.data << " " << param.buf << " type:" << typeid(param).name()<< endl;
}else{
printf("err, though equal,but not reg, %s\n", typeid(T1).name());
}
} template < typename T1, typename T2 > void foo(T1 param, T2 param2) {
//if(typeid(Test2).name() == typeid(param).name()){
if(typeid(T2) == typeid(T1)){
param.data = ;
param2.data = ;
printf("param:%d, param2:%d\n", param.data, param2.data);
}else if ( typeid(Test2) == typeid(param2)) {
param2.data = ;
string str("Test2 copy");
strncpy(param2.buf, str.c_str(), str.size());
cout << "int:" << param2.data << " " << param2.buf << " type:" << typeid(param2).name()<< endl;
} else{
printf("err, though equal,but not reg, %s\n", typeid(T1).name());
}
}
};

AdapterEx.hpp

 #ifndef _PROXY_H_
#define _PROXY_H_
#include <string>
#include <string.h>
using namespace std; struct Test{
int data;
//string str;
float f;
}; struct Test2{
int data;
//string str;
char buf[];
Test2(){
data = ;
memset(buf, 0x00, sizeof(buf));
}
}; #endif

solution.h

C++中hpp的适用的更多相关文章

  1. Python开源框架

    info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...

  2. caffe中的filler.hpp源码的作用:

    filler.hpp文件:(它应该没有对应的.cpp文件,一切实现都是在头文件中定义的,可能是因为filler只分在网络初始化时用到那么一次吧) 1,首先定义了基类:Filler,它包括:一个纯虚函数 ...

  3. c++中的.hpp文件

    http://blog.chinaunix.net/uid-24118190-id-75239.html hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的 ...

  4. C++中.cpp和.hpp的区别

    原文地址:https://blog.csdn.net/qzx9059/article/details/89210571 c++中 cpp和hpp我们可以将所有东西都放在一个.cpp文件内,编译器会将这 ...

  5. android studio 使用 jni 编译 opencv 完整实例 之 图像边缘检测!从此在andrid中自由使用 图像匹配、识别、检测

    目录: 1,过程感慨: 2,运行环境: 3,准备工作: 4,编译 .so 5,遇到的关键问题及其解决方法 6,实现效果截图. (原创:转载声明出处:http://www.cnblogs.com/lin ...

  6. 基于Caffe的DeepID2实现(中)

    小喵的唠叨话:我们在上一篇博客里面,介绍了Caffe的Data层的编写.有了Data层,下一步则是如何去使用生成好的训练数据.也就是这一篇的内容. 小喵的博客:http://www.miaoerduo ...

  7. [Modern OpenGL系列(四)]在OpenGL中使用Shader

    本文已同步发表在CSDN:http://blog.csdn.net/wenxin2011/article/details/51347440 在上一篇文章中已经介绍了OpenGL窗口的创建.本文接着说如 ...

  8. 学习 opencv---(8)非线性滤波:中值滤波,双边滤波

    正如我们上一篇文章中讲到的,线性滤波可以实现很多种不同的图像变换.然而非线性滤波,如中值滤波器和双边滤波器,有时可以达到更好的实现效果. 邻域算子的其他一些例子还有对 二值图像进行操作的形态学算子,用 ...

  9. opencv中的SIFT,SURF,ORB,FAST 特征描叙算子比较

    opencv中的SIFT,SURF,ORB,FAST 特征描叙算子比较 参考: http://wenku.baidu.com/link?url=1aDYAJBCrrK-uk2w3sSNai7h52x_ ...

随机推荐

  1. Indidual Homework Assignment

    一.Pair work的得与失 合作编程在以前的学习过程中也进行过,基本也就是各人负责一部分最后再将之拼凑起来,而这次作业要求的双人合作,要求的并不是这样,而是两人应该在一起进行工作,这样的要求理想情 ...

  2. 【实践报告】Linux实践二

    3.编译并安装内核与模块 sudo make bzImage –j3         编译内核 sudo make modules –j3         编译模块 sudo make modules ...

  3. Linux 第八周实验 进程的切换和系统的一般执行过程

    姬梦馨 原创作品 <Linux内核分析>MOOC课程:http://mooc.study.163.com/course/USTC-1000029000 第八讲 进程的切换和系统的一般执行过 ...

  4. SpringBoot-简单实例

    在进行实例之前,首先须确保电脑环境变量已经配置好,包括jdk.maven.此文章不做描述,不清楚自行百度. 第一步:来到springboot官网(https://start.spring.io/)下载 ...

  5. PAT 1013 数素数

    https://pintia.cn/problem-sets/994805260223102976/problems/994805309963354112 令P~i~表示第i个素数.现任给两个正整数M ...

  6. [转帖]git、github、gitlab之间的关系

    Git - 版本控制工具 Github - 一个网站,提供给用户空间创建git仓储,保存用户的一些数据文档或者代码等 GitLab - 基于Git的项目管理软件 Git分布式版本控制系统 Git是一款 ...

  7. p3c安装使用 编码规范扫描 阿里巴巴出品,挺好用的

    https://github.com/alibaba/p3c/wiki/IDEA%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3

  8. ceph 搭建nginx负载3个对象网关

    nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid ...

  9. Django-website 程序案例系列-15 singnal分析

    在django框架中singnal的应用相当于在你执行某些重要函数语句时在这条语句的前后放置两个预留的钩子,这两个钩子就是singnal,这个钩子也可以理解成两个触发器,当出现执行语句前后是触发执行某 ...

  10. Code First 重复外键(简单方法)

    之前有说过  Code First 重复外键   的一种解决方案.   http://blog.csdn.net/hanjun0612/article/details/50478134 虽然可以解决问 ...