文档章节

女神经之C++自学之路 (关于句柄)

 女神经
发布于 2017/03/30 18:56
字数 1819
阅读 2276
收藏 61

前言:作为一个C++的新手,希望可以通过自己的努力,变得更好!

刚接触到句柄,对句柄的理解很浅显;就是减少重复编译而产生的;如果我们改动了某个头文件,那么所有包含这个头文件的相关文件都得进行重新编译、连接等等等,这在大项目中,是非常耗费时间的;

使用句柄类(头文件和接口都不变,有一个指向结构的指针),只改动实现的部分,我们可以对句柄实现的方法进行修改,但保持头文件和公共的接口不改变,这也就是可以减少不必要的编译时间;

句柄要如何使用呢?接下来我将根据自己的理解写一小段代码。

实验一:

  • 先将我们要写的句柄的头文件定义好
#ifndef NSJHANDLE_H
#define NSJHANDLE_H

#include <iostream>

using namespace std;
class NSJHandle
{
public:
    NSJHandle();
    struct  Handle1;  //在这里我们先声明了一个Handle1的结构体,不需要手动加载typedef,oop编译器会自动加载
    Handle1 *pNsjHandle;//接着,我们在这里指明Handle1结构体指针

    void init();   //这些都是我们要公开的接口
    void read();
    void setData();
};

#endif // NSJHANDLE_H
  • 句柄对应的.cpp文件 
#include "nsjhandle.h"
#include <stdlib.h>
#include<QDebug>
NSJHandle::NSJHandle()
{
   init();
}

struct NSJHandle::Handle1{  //这里就是我们刚才在头文件中没有定义的结构体,在这里定义,用来隐藏我们的数据
public:
    void setData(int tmpData1);  
    int  getData();
private:
    int      data1;
    double   data2;
};

void NSJHandle::init()  //初始化结构体
{
    pNsjHandle = (Handle1*)malloc(sizeof(Handle1));
}

void NSJHandle::read() //读取数据
{
    if(pNsjHandle) cout<<"data1:"<<pNsjHandle->getData()<<endl;
}

void NSJHandle::setData() //设置数据
{
    if(pNsjHandle) pNsjHandle->setData(10);
}

void NSJHandle::Handle1::setData(int tmpData1)
{
    data1 = tmpData1;
}

int NSJHandle::Handle1::getData()
{
    return data1;
}
  • 在main 函数中调用
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "nsjhandle.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void test();

private:
    Ui::MainWindow *ui;
    NSJHandle pDemoHandle; //定义一个句柄类对象
};
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <iostream>
std::string num;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    pDemoHandle.setData(); //对公开的接口进行调用
    pDemoHandle.read();

}

MainWindow::~MainWindow()
{
    delete ui;
}
  • 打印出来的结果:

实验二:

偶然看见别人封住好留出来的接口,突然想说,能不能自己也模拟出他们预留出来的接口。先上代码:

  • 先定义一个抽象类:这是我们暴露出来给别人的公共接口
#ifndef NSJHANDLE_H
#define NSJHANDLE_H

#include <iostream>

using namespace std;
class NSJHandle
{
public:
    virtual  void  read() = 0;
    virtual  void  setData() = 0;
};

extern "C"{
   NSJHandle *creatorHandleType(int type); //我们可能需要根据业务逻辑,故给个类型进行区分返回的句柄的类型
}

#endif // NSJHANDLE_H
#ifndef NSJINHERITHANDLE_H
#define NSJINHERITHANDLE_H
#include"nsjhandle.h"

using namespace std;
class NSJInheritHandle : public NSJHandle   //基础抽象类NSJHandle的派生类 
{
public:
    NSJInheritHandle();
    ~NSJInheritHandle();
    struct  Handle1;
    Handle1 *pHandle;
    void  init();
    void  read();
    void  setData() ;
};

#endif // NSJINHERITHANDLE_H
  • 派生类的.cpp文件
#include "nsjinherithandle.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <QDebug>
NSJInheritHandle::NSJInheritHandle()
{

}

NSJInheritHandle::~NSJInheritHandle()
{
    if(pHandle){
        delete pHandle;
        pHandle = nullptr;
    }
}

struct NSJInheritHandle::Handle1{
public:
    void setData(int tmpData1);
    int  getData();
private:
    int      data1;
    double   data2;
};

void NSJInheritHandle::init()
{
    pHandle = (Handle1*)malloc(sizeof(Handle1));
}

void NSJInheritHandle::read()
{
    if(pHandle) cout<<"data1:"<<pHandle->getData()<<endl;
}

void NSJInheritHandle::setData()
{
    if(pHandle) pHandle->setData(10);
}

void NSJInheritHandle::Handle1::setData(int tmpData1)
{
    data1 = tmpData1;
}

int NSJInheritHandle::Handle1::getData()
{
    return data1;
}

NSJHandle *creatorHandleType(int type){  //我们在派生类中,将生成派生类的指针传出去
    if(0 == type){
       NSJInheritHandle *inheritHandle = new NSJInheritHandle;
       inheritHandle->init();
       return inheritHandle;
    }
}
  • main函数中调用
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <iostream>
#include "nsjinherithandle.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

  NSJHandle * handle = creatorHandleType(0); //通过我们指定的对象
  handle->setData();
  handle->read();
}

MainWindow::~MainWindow()
{
    delete ui;
}

这样,结果跟之前的是一致的。

  • 总结

  • 在这个代码的编写过程中,有两个C++的基础是需要我们知道的

  • 1)什么是虚函数?什么是纯虚函数?有什么需要注意的地方?
  • 2)new和malloc直接的区别是什么,在C++中如果使用不当会造成什么样的问题?

        首先,根据我编写的过程出现的错误,来一步步的查找和理解这些问题;

  • 1)什么是虚函数?什么是纯虚函数?有什么需要注意的地方? 

         (1) 虚函数:简单的理解就是被virtual修饰的成员函数,是为了实现多态性而产生的;目的很简单,就是为了接口与具体实现的分离,使用同名函数,但因对象个体不同而指向相对应的函数;

           

class A{
   virtual void fun();
}

class B : public A{
   void fun();
} 
class C : public A{
   void fun();
} 

 

         (2)纯虚函数:就是在类声明的时候定义一个函数声明,但不被定义实现,是留着给继承它的派生类实现的,派生类一定的定义基类中的纯虚函数,不然该对象不能被实例化;纯虚函数的书写很简单,就是在虚函数的基础上,在函数体后面加上 “= 0”这个后缀,用来标记其是纯虚函数;

class A{
   virtual void fun() = 0; //纯虚函数,函数声明但不定义,只是占个位置
}

class B : public A{
   void fun();
} 
class C : public A{   //直接报错,因为没有将定义一个跟纯虚函数相同的函数
 
} 
  • 2)new和malloc直接的区别是什么,在C++中如果使用不当会造成什么样的问题?
  • 这个问题一开始我也觉得没什么,就是知道C++兼容C,其实new和malloc是一样的,都是在堆上分配一堆内存;就是因为对这个基础的概念不了解,导致我的程序一直段错误;先将代码贴上
  • NSJHandle *creatorHandleType(int type){       //这段使用的是C++中的new
        if(0 == type){
           NSJInheritHandle *inheritHandle = new NSJInheritHandle;
           inheritHandle->init();
           return inheritHandle;
        }
    }
    
    NSJHandle *creatorHandleType(int type){        //这段使用的是C中的malloc
        if(0 == type){
           NSJInheritHandle *inheritHandle =(NSJInheritHandle *)malloc(sizeof(NSJInheritHandle));
           inheritHandle->init();
           return inheritHandle;
        }
    }
    
    //以上是两种不同的方式,通过下面那段代码来进行调用
    
    NSJHandle * handle = creatorHandleType(0);
    handle->setData();
    handle->read();
    
    //结果:第一段代码是成功的,而第二段代码是失败的,会报段错误。。。
    
          我就纳闷了,怎么,这两者怎么就会有如此大的差别,不都是分配内存返回指针吗?
  • 后来查了下资料,才知道new和malloc的差别还是蛮大的;我们接下来就简单的来说说他们之间的差距哈。

          (1)new和malloc最大的差距就在于:malloc是直接在堆上分配一段内存,而new出了分配内存外,它还会调用类的构造函数;这就是他们之间最大的区别。

new的功能 创建了一个对象,分配内存 调用构造函数
malloc的功能 分配内存  
 delete的功能 删除了一个对象,释放内存 调用析构函数
free的功能 释放内存  

   

new \ delete new是保留字,不需要加载头文件;new delete 是运算符;
malloc \ free malloc是需要头文件支持的; malloc,free是函数

   注意点:我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。

如果不对的地方,欢迎大家来打。。,不对,是来告诉我,别让我陷入其中,不可自拔

好啦,女神经要睡觉了。。。。。。。。。。。。。。。

               

© 著作权归作者所有

粉丝 27
博文 1
码字总数 1819
作品 0
广州
私信 提问
加载中

评论(40)

巭
这个其实和句柄没关系,你保证你导出的那个类的内存布局不发生改变才是本质。
byNcz
byNcz
現在win桌面程序應該用wpf多些吧
不愿透露姓名的Mr成
不愿透露姓名的Mr成
女神教教我吧,我是做java的想跟你学学C++@女神经
hell0cat
hell0cat

引用来自“hell0cat”的评论

真心希望各位:少给点建议、少列些书单,多贴些代码,多给些鼓励。

引用来自“刘大神”的评论

说的就好像我给你代码 你能看懂一样
不是给我看,是给人家博主看!我没兴趣看你的代码,写的再好我也不看
刘大神
刘大神

引用来自“hell0cat”的评论

真心希望各位:少给点建议、少列些书单,多贴些代码,多给些鼓励。
说的就好像我给你代码 你能看懂一样
vector_ming
vector_ming
推荐一本 c++从入门到放弃
😬
不错啊 继续努力. c++的程序媛很少啊
garywlx
garywlx
只要有兴趣,坚持下去就好 。。。
曾经的十字镐
曾经的十字镐
问句柄和文件描述符有何区别?
OSC_GssVlE
OSC_GssVlE
mark~
【Visual C++】CDC与HDC的区别以及相互转换

CDC是MFC的DC的一个类 HDC是DC的句柄,API中的一个类似指针的数据类型. MFC类的前缀都是C开头的 H开头的大多数是句柄 这是为了助记,是编程读\写代码的好的习惯. CDC中所有MFC的DC的基类.常用的...

长平狐
2012/11/12
101
0
笑脸识别从零开始研究:优美的程序(2)

近几个月的笑脸识别研究过程中踩了很多坑,担心记录在本地容易不小心给删了,记录一份放在网上 回顾学习之路,程序上从C++开始,到执着于Python,从实现简单的图像剪切到自己构建卷积神经网络...

刘必王A6
2018/06/18
0
0
如何在dll中添加资源

文章转载自http://blog.csdn.net/na_he/article/details/2451822 在DLL中使用资源 现在最常看见的关于DLL的问题 就是如何在DLL中使用对话框,这是一个很普遍的关于如何在DL L中使用资源的...

长平狐
2012/10/08
881
0
揭秘!为何要用_beginthreadex,而不用CreateThread和_beginthread

由于历史原因,所以C/C++运行库并不是为多线程应用程序而设计的,所以为了保证其中的某些变量和函数的安全,那么必须创建一个数据结构,并使之与使用了C/C++运行库函数的每个线程所关联。当在...

shzwork
03/06
5
0
Chrome嵌入MFC窗口后MFC无法响应ESC键关闭窗口消息

Chrome嵌入MFC窗口后该MFC窗口无法响应ESC键关闭窗口消息。CEF3中OnPreKeyEvent的参数os_event中的窗口句柄也与MFC窗口句柄、chrome浏览器句柄都不匹配。win7 64位操作系统。请大侠们赐教!...

wz08lb
2016/03/14
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

全面兼容IE6/IE7/IE8/FF的CSS HACK写法

浏览器市场的混乱,给设计师造成很大的麻烦,设计的页面兼容完这个浏览器还得兼容那个浏览器,本来ie6跟ff之间的兼容是很容易解决的。加上个ie7会麻烦点,ie8的出现就更头疼了,原来hack ie...

前端老手
15分钟前
3
0
常用快递电子面单批量打印api接口对接demo-JAVA示例

目前有三种方式对接电子面单: 1.快递公司:各家快递公司逐一对接接口 2.菜鸟:支持常用15家快递电子面单打印 3.快递鸟:仅对接一次,支持常用30多家主流快递电子面单打印 目前也是支持批量打...

程序的小猿
19分钟前
6
0
Yii 框架中rule规则必须搭配验证函数才能使用

public $store_id;public $user_id;public $page;public $limit;public $list;public $mch_list;public $cart_id;public $is_community;public $shop_id;public $cart_typ......

chenhongjiang
21分钟前
4
0
Flutter使用Rammus实现阿里云推送

前言: 最近新的Flutter项目有“阿里云推送通知”的需求,就是Flutter的App启动后检测到有新的通知,点击通知栏然后跳转到指定的页面。在这里我使用的是第三方插件Rammus来实现通知的推送,之...

EmilyWu
21分钟前
41
0
Knative 实战:三步走!基于 Knative Serverless 技术实现一个短网址服务

短网址顾名思义就是使用比较短的网址代替很长的网址。维基百科上面的解释是这样的: 短网址又称网址缩短、缩短网址、URL 缩短等,指的是一种互联网上的技术与服务,此服务可以提供一个非常短...

阿里巴巴云原生
36分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部