前言:作为一个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是等价的。
如果不对的地方,欢迎大家来打。。,不对,是来告诉我,别让我陷入其中,不可自拔
好啦,女神经要睡觉了。。。。。。。。。。。。。。。