虚函数实际应用

业务场景

用户需要设定规则,我们根据用户输入的数值判断是否符合规则。
示例一:
用户认为满足如下条件的属于合格品:

13.25<width<62.15 &&69.35> height>9.278 && area>5.86

(数字我随便敲的)

现在来了一批样品,得到了属性width等的数值。要判断样品是否合规

设计

我的思路:针对每个属性都定义一个函数,由用户设定其取值范围,输入数值判断是否合格。类似于
初始化一个函数: widthfun(double min, double max)
输入数值判断 是否 min<value<max

有多少个属性就需要多少函数

用一个工厂类创建需要的属性函数,存储到map里,等数值来了之后,由工厂函数判断是否合格。

接口类

IDefectFilterInterface

假设有三个属性,肯定不能直接写三个属性类。因为我希望用户输入数值,根据数值的属性,知道调用哪个属性函数。所以有一个指针p,能调用所有的属性函数。
那么就需要一个基类,判断数值的函数设置为虚函数。我在工厂类中能用基类的指针p,调用派生类的函数判断数值。

判断数值是否合格的函数定义为

virtual bool IsFilter(QVariant varValue) = 0;

由于该函数必须被子类实现,所以这里定义为纯虚函数(不实现这个类就没有意义)
接口 IDefectFilterInterface就定义好了

IDefectRangeFilterInterface

初始化属性类还需要用户输入取值范围:min<value<max
这里新建一个IDefectRangeFilterInterface 继承IDefectFilterInterface
在IDefectRangeFilterInterface 新加一个设置范围的纯虚函数

virtual void SetDefectFilterRange(QVariant minValue, QVariant maxValue) = 0;

因为不确定用户需要的数据类型是 double 还是int 还是其他,这里就使用qt自带的QVariant ,它可以转化为基础类型。
还需要两个成员变量存储最大最小值

QVariant m_minValue;
QVariant m_maxValue;

派生类

CDefectRangeFilter

继承IDefectRangeFilterInterface
因为使用QVariant 所以设置取值范围时,还不需要考虑数据类型的问题,直接赋值即可

void CDefectRangeFilter::SetDefectFilterRange(QVariant minValue, QVariant maxValue)
{
    
    
	m_minValue = minValue;
	m_maxValue = maxValue;
}

CDefectINTRangeFilter

最后因为我的属性目前都是 int型,所以定义一个 int型的属性类 CDefectINTRangeFilter
这里只需要继承CDefectRangeFilter,并实现

bool CDefectINTRangeFilter::IsFilter(QVariant varValue)
{
    
    
	bool bIsFilter = true;
	qint32 iValue = varValue.toInt();
	qint32 iMinValue = m_minValue.toInt();
	qint32 iMaxValue = m_maxValue.toInt();
	if(iValue > iMinValue  && iValue <iMaxValue )
	{
    
    
	return true;
	}
	else
	return false;
}

在这里插入图片描述

工厂类

我们要怎么使用呢?
在类中定义一个map用来存放属性类

QMap<QString, IDefectFilterInterface*> m_mapFilter;

这里使用基类IDefectFilterInterface 指针,为了方便调用IsFilter函数

用户给每个属性类设置取值范围

//初始化map
void CDefectFilterFactory::init()
{
    
    
	//1. 创建宽度类
	IDefectFilterInterface* pClassWidth = new CDefectINTRangeFilter();
	// 添加到Map
	m_mapFilter.insert("width", pClassWidth);

	//2. 创建高度类
	IDefectFilterInterface* pClassHeight = new CDefectINTRangeFilter();
	// 添加到Map
	m_mapFilter.insert("height", pClassHeight);

	//3. 创建面积类

	IDefectFilterInterface* pClassArea = new CDefectINTRangeFilter();
	// 添加到Map
	m_mapFilter.insert("area", pClassArea);
}

void CDefectFilterFactory::setRange(QMap<QString,QPair<QVariant ,QVariant >> ranges)
{
    
    
....
pClass = m_mapFilter[type];
// 转换类指针
IDefectRangeFilterInterface* pDefectRangeFilterClass = dynamic_cast<IDefectRangeFilterInterface*>(pClass);
...
pDefectRangeFilterClass->SetDefectFilterRange(varMin, varMax);
}

这里虚函数的好处就出来了
我们可以把基类IDefectFilterInterface指针,用dynamic_cast转成IDefectRangeFilterInterface指针,调用虚函数SetDefectFilterRange就可以设置取值范围

查看是否合格同样的只需要传入 属性 "width"和数值 23.45
在m_mapFilter中找到对应的属性类即可

IDefectFilterInterface* pClass = m_mapFilter[type];
return pClass->IsFilter(varValue);

虚函数原理

C++虚函数的实现机制
C++多态的底层原理
(巨详细 + 图解) C++多态的机制原理
总结
我们用派生类CDefectINTRangeFilter new一个对象出来时 ,该指针的虚表是派生类的虚表

IDefectFilterInterface* pClassWidth = new CDefectINTRangeFilter();

当我们用 基类指针指向派生类时,虚表没有改变

// 转换类指针
IDefectRangeFilterInterface* pDefectRangeFilterClass = dynamic_cast<IDefectRangeFilterInterface*>(pClass);

我们再做一次类型转换时,虚表还是原来的样子,所以它可以调用子类的虚函数

猜你喜欢

转载自blog.csdn.net/fuyouzhiyi/article/details/127225152