设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

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

2017-3-30 21:43| 发布者: joejoe0332| 查看: 1275| 评论: 0|原作者: oschina|来自: oschina

摘要: 作为一个C++的新手,希望可以通过自己的努力,变得更好!刚接触到句柄,对句柄的理解很浅显;就是减少重复编译而产生的;如果我们改动了某个头文件,那么所有包含这个头文件的相关文件都得进行重新编译、连接等等等, ...

前言:作为一个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 \ deletenew是保留字,不需要加载头文件;new delete 是运算符;
malloc \ freemalloc是需要头文件支持的; malloc,free是函数

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

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

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


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部