第一、多态与继承
1 静态多态
静态动态:函数重载和运算符重载,复用函数名
2 动态多态
动态多态:派生类和虚函数实现运行时多态
让我们用代码来演示:
#include <iostream>
using namespace std;
//动态多态的满足关系:
//1 有继承关系
//2 子类重写父类中的虚函数 virtual
class Animal
{
public:
virtual void speak()//父类用虚函数,并且子类重写了此函数,使得其地址晚绑定
{
cout<<"动物在说话"<<endl;
}
};
class Cat:public Animal
{
public:
void speak()
{
cout<<"猫在说话"<<endl;
}
};
class Dog:public Animal {
public:
void speak()
{
cout<<"狗在说话"<<endl;
}
};
void DoSpeak (Animal&animal)//动态多态的使用 ,用父类的指针或者引用来接收子类对象
//如果父类函数加了virtual,子类调用父类函数,父类的虚函数指针vfptr指向的虚函数表
//虚函数表里会有Cat::speak,如果Cat不重写speak函数,虚函数表里还是Animal::speak
{
animal.speak();
}
void test01()
{
Cat cat;
DoSpeak(cat);
Dog dog;
DoSpeak(dog);
}
void test02()
{
cout<<"sizeof:"<< sizeof(Cat);//不给Animal函数里加virtual,size为1,成员函数不占用类的储存
//而加了virtual之后,这是一个vfptr指针,即虚函数(表)指针,size为8
}
int main()
{
test01();
test02();
system("pause");
return 0;
}
第二、C++的接口
1、类接口的定义 通常在头文件中完成类接口的定义 /*InterfaceDefineAndRealize.h*/
#ifndef INTERFACE_DEFINE_AND_REALIZE
#define INTERFACE_DEFINE_AND_REALIZE
#include <string>
using std::string;
//define interface
class Person
{
public:
Person():m_StrName("###") //成员列表初始化参数
{};
virtual ~Person(){};
virtual void Eat()=0;//人需要吃东西
virtual void Sleep()=0;//人需要睡觉
virtual void SetName(const string strName)=0;//人都有名字
virtual string GetName()=0;//获取名字
virtual void Work()=0;//人可能要有工作
private:
string m_StrName;
};
//实现接口
//实现接口是通过派生类实现的,每个派生类依据自身特点,可以获取同一接口的不同实现
//也就是所谓的多态
class Student:public Person
{
public:
Student():m_strName("***")
{};
~Student()
{};
void Eat();
void Sleep();
void SetName(const string strName);
string GetName();
void Work();
private:
string m_strName;
};
#endif
2、 接口的实现 通常在源文件中完成接口的实现 /*InterfaceDefineAndRealize.cpp*/
#include "InterfaceDefineAndRealize.h"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
//接口的外部实现
void Student::Sleep()
{
cout<<"student sleep."<<endl;
}
void Student::Eat()
{
cout<<"student eat."<<endl;
}
void Student::SetName(const string strName)
{
m_strName=strName;
}
void Student::Work()
{
cout<<"student work."<<endl;
}
string Student::GetName()
{
return m_strName;
}
//需要导出的函数,即用户在外部可以调用的接口
_declspec(dllexport)bool GetPersonObject(void** _RtObject)
{
Person* pMan=NULL;
pMan=new Student();
*_RtObject=(void*)pMan;
return true;
}
3 、接口的导出 通常在模块定义文件中完成 /*InterfaceDefineAndRealize.def*/
LIBRARY InterfaceDefineAndRealize
EXPORTS
GetPersonObject
新建项目,加载上述三个文件,设置项目属性—>配置属性——>常规——>配置类型 ,选择"动态库.dlll",生成可用的动态库,假如项目名称为InterfaceDefineAndRealize(注意:项目名称必须与模块定义文件中 LIBRARY 后面定义的名字相同,否则将导致出现无法找到动态库的错误。),则在该项目的当前工作目录下位生成动态库和它的导入库。
4、接口的调用
为了与常规的调用动态库的方式保持一致,这里做一些额外工作。新建“include”文件夹,并将InterfaceDefineAndRealize.h放到此文件夹下,新建“lib”文件夹并将InterfaceDefineAndRealize.lib文件放到此文件夹下。新建项目UsingInterface,添加源文件实现调用接口的功能。
4.1 为项目添加附加包含目录
方法1:项目属性——>配置属性——>C/C++——>常规——>附加包含目录 将include文件夹的全路径添加进来。
方法2:项目属性——>配置属性——>VC++目录——>包含目录 中将include文件夹的全路径添加进来。
4.2 为项目添加附加库
方法1:项目属性——>配置属性——>链接器——>常规——>附加库目录 将lib文件夹的全路径添加进来。
方法2:项目属性——>配置属性——>VC++目录——>库目录 将lib文件夹的全路径添加进来。
注意:2.1中的方法1与2.2中的方法1对应,2.1中的方法2与2.2中的方法2对应,不能不换使用。
4.3 为项目添加导入库
项目属性——>配置属性——>链接器——>输入——>附加依赖项 中添加InterfaceDefineAndRealize.lib
4.4 为项目提供动态库
将生成的.dll动态库放到项目的当前目录下的Debug目录下,防止出现缺少动态库的错误。
4.5 编写代码,实现接口的调用
#include <iostream>
#include "InterfaceDefineAndRealize.h"
bool _declspec(dllimport) GetPersonObject(void** _RtObject);
int main()
{
Person* person=NULL;
void* pObj=NULL;
if(GetPersonObject(&pObj))//调用接口
{
person=(Person*)pObj;
person->Eat();
person->Sleep();
person->SetName("zhang hui");
std::cout<<person->GetName()<<std::endl;
person->Work();
if(person!=NULL)
{
delete person;
person=NULL;
}
}
system("pause");
return 0;
}
完!