MyMathFun.h
#pragma once // #ifdef DLLCLASS_API // #define DLLCLASS_API _declspec(dllimport) // #else // #define DLLCLASS_API _declspec(dllexport) // #endif #define DLLCLASS_API _declspec(dllexport) class DLLCLASS_API MyMathFun { public: MyMathFun(void); ~MyMathFun(void); double Add(double a,double b); double Substract(double a,double b); double Multiply(double a,double b); double Divide(double a,double b); };
MyMathFun.cpp
#include "MyMathFun.h" #include <stdexcept> using namespace std; MyMathFun::MyMathFun(void) { } MyMathFun::~MyMathFun(void) { } double MyMathFun::Add(double a,double b) { return a+b; } double MyMathFun::Substract(double a,double b) { return a-b; } double MyMathFun::Multiply(double a,double b) { return a*b; } double MyMathFun::Divide(double a,double b) { if (b==0) { throw new invalid_argument("b cannot be zero!"); } return a/b; }
程序调用:
#include <iostream> using namespace std; //当使用添加头文件目录,以便程序中包含的头文件存在(即可以找到): //1.项目,属性->C/C++->常规->附加包含目录:..\MathFunDll //2.#include "MyMathFun.h" 就可以省略下面的类的再次声明了 #define DLLCLASS_API _declspec(dllimport) class DLLCLASS_API MyMathFun { public: MyMathFun(void); ~MyMathFun(void); double Add(double a,double b); double Substract(double a,double b); double Multiply(double a,double b); double Divide(double a,double b); }; void main() { MyMathFun* mFun=new MyMathFun(); cout<<mFun->Add(1,2)<<endl;//3 cout<<mFun->Substract(3,4)<<endl;//-1 cout<<mFun->Multiply(5,6)<<endl;//30 cout<<mFun->Divide(7,8)<<endl;//0.875 }
需要注意的地方:
1,不直接生成类的实例。对于类的大小,当我们定义一个类的实例,或使用new语句生成一个实例时,内存的大小是在编译时决定的。要使应用程序不依赖于类的大小,只有一个办法:应用程序不生成类的实例,使用DLL中的函数来生成。把导出类的构造函数定义为私有的(privated),在导出类中提供静态 (static)成员函数(如NewInstance())用来生成类的实例。因为NewInstance()函数在新的DLL中会被重新编译,所以总能返回大小正确的实例内存。
2,不直接访问成员变量。应用程序直接访问类的成员变量时会用到该变量的偏移地址。所以避免偏移地址依赖的办法就是不要直接访问成员变量。把所有的成员变量的访问控制都定义为保护型(protected)以上的级别,并为需要访问的成员变量定义Get或Set方法。Get或Set方法在编译新DLL时会被重新编译,所以总能访问到正确的变量位置。
3,忘了虚函数吧,就算有也不要让应用程序直接访问它。因为类的构造函数已经是私有(privated)的了,所以应用程序也不会去继承这个类,也不会实现自己的多态。如果导出类的父类中有虚函数,或设计需要(如类工场之类的框架),一定要把这些函数声明为保护的(protected)以上的级别,并为应用程序重新设计调用该虑函数的成员函数。这一点也类似于对成员变量的处理。
所以在创建类指针或者对象时,最好是在类里面的实例函数来创建,下面上一个创建类指针的例子:我这里以类CSetting为例子
首先在类的头文件public下创建函数static CSetting* GetInstace();
接着在类的头文件下面新建private,在里面创建类指针,定义:static CSetting* m_pInstance;
接着在cpp文件中初始化一下指针,一般赋空 CSetting* CSetting::m_pInstance = NULL;(不在构造函数中初始化,放在包含文件下面即可)
在cpp文件的析构函数中,添加指针释放:
CSetting::~CSetting() { if(m_pInstance) { delete m_pInstance; m_pInstance = NULL; } }
接着最后一步,创建函数GetInstance(),代码如下:
CSetting* CSetting::GetInstace() { if(NULL == m_pInstance) { m_pInstance = new CSetting; } return m_pInstance; }
在其他程序代用此类的时候可以使用CSetting::GetInstance()来调用类里面的方法和属性
完成!