CPP的接口非虚原则(NVI)

本文探讨了C++中非虚接口模式(NVI)的设计思想,对比了虚函数与非虚函数的应用场景,并分析了如何在基类中更好地控制接口行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这段时间翻设计思想类的书发现,上面都提到,C++对象模型中,接口跟虚函数,二者只能选其一,就是说,要么一个公有方法是非虚的,要么一个私有方法是虚的,不建议出现公有的虚函数,如果要这样建议写个公有转接口,转发调用到私有的函数中去。以下是参考资料:

对于常规的基类函数来说:

1 尽量使用非虚拟接口模式(NVI)让接口函数成为非虚拟的

2 尽量让虚函数成为私用的

3 只有当派生类需要调用基类对某个虚函数的实现时,才把虚函数声明为保护的。

4 基类的析构函数应该要么为共有虚函数,要么为保护虚函数。

说明;12两条将虚公有接口的两个职责进行了很好的分解,遵守了单一职责原理。

  第4条说明了:如果要使用多态(指针调用),那么基类的析构函数一定要为虚函数;如果基类本身的设计不是处于多态考虑的话,那么就应该将析构函数设为保护类型。这样可防止出现使用指针的析构(基类无法被直接析构),只有派生类才能析构基类。

1) 非虚接口模式(NVI)的说明:基类对接口具有完全控制权,很方便在一个单一的、可复用的地方实施(enforce)接口的前条件。后条件、插入一些设备或做一些类似的事情。更好的是实现接口和实现分离;让基类在变化面前更稳定。条件检查可以仅在调式期有效,这更易于控制。如果非虚函数仅有唯一一行转发调用,编译器会做内联优化,没有效率问题。

从上面看出,理由主要在接口的控制权,如果基类需要保留接口的控制权(例如某天想在接口前加一段代码),则不应该声明为虚函数。

一下代码说明:

class CBase
{
private:
       int m_iCnt;
public:
       //虚函数接口
       virtualint add(int a,int b)
       {
              returna + b;
       }
};


 

如果突然我想统计这个接口被调用次数,由于是虚函数,只能到每个派生类中增加代码:

virtual int add(int a,int b)
{
         m_iCnt++;                //增加的代码,每个子类都需要
         return a + b;
}


 如果接口是非虚的,例如

class CBase
{
private:
	int m_iCnt;
	//虚函数接口
	virtual int doAdd(int a,int b)
	{
		return a + b;
	}
public:
	int Add(int a,int b)
	{
		return doAdd(a,b)
	}

};

那么只需要增加一句:

	int Add(int a,int b)
	{
		m_iCnt++; //增加一句
		return doAdd(a,b)
	}


注意到,上面只是说尽量 其实个人认为,按照实际需要,如果基类的确需要保留接口控制权,那么就遵循,如果不需要,直接用纯虚接口也无妨。例如 Java,C#的接口(interface),Objective-C中的协议(Protocol),其实就是C++中的一个全部是纯虚函数的类,既然这些面向对象语言有类似的存在,那么必定有其存在的理由。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值