C++程序的设计机制1 NVI机制
C++程序的设计机制1 NVI机制
我们都知道在C++程序设计中,存在一些设计开发的机制。本文主要介绍其中的NVI机制,也就是Non-Virtual Interface,希望对你有帮助,一起来看。
AD:
在C++的程序设计中有一些设计开发的典型机制需要整理讨论,在此抛砖引玉,为自己做积累,请高人也多多指教。
1.简介
在标准C++库中我们可以看到这样的一个现象:
6个公有虚函数,并且都是std::exception::what()和其重载。
142个非公有虚函数。
这样设计的目的何在呢,为什么“多此一举”的把虚函数设置为非公有呢?
这就是NVI机制要求的:将虚函数声明为非公有,而将公有函数都声明为非虚——虚拟和公有选其一。
2.机制分析
程序员常常将基类中的虚函数公有化,来提供一个接口的定义(virtual的功劳)同时提供其实现(具体的一个实现)。
- class Base{
- public:
- virtual void Foo(int){
- cout<< "Base's Foo!" << endl;
- };
- };
问题就出在“同时”——一个定义了接口的形式,一个定义了默认的一个实现,显然这样的设计没有将接口定义和实现分来。在这个时候,我们可以使用模板方法模式的思想:
- class Base{
- public:
- void Foo(){
- DoFoo1();
- DoFoo2();
- }//use DoFooX()
- private:
- virtual void DoFoo1(){
- cout << "Base's DoFoo1" <<endl;
10.}
11.virtual void DoFoo2(){
12.cout << "Base's DoFoo2" <<endl;
13.}
14.};
15.class Derived: public Base{
16.private:
17.virtual void DoFoo1(){
18.cout << "Derived's DoFoo1" << endl;
19.};
20.};
函数Foo定义了接口的形式,而DoFooX()函数则实现了对Foo函数的行为定制,实现了接口定义和实现的分离,我们举一个例子来说明好处:如果我们希望在Foo中做一下CS(Critical Section)的加锁解锁控制:
若我们完成这样的接口与实现分离,那么我们的实现是在基类的接口处添加所需流程即可,子类不需要修改:
- class Base{
- public:
- void Foo(){
- cout << "Locking" << endl;
- DoFoo1();
- DoFoo2();
- cout << "Unlocking" << endl;
- }//use DoFooX()
- private:
10.virtual void DoFoo1(){
11.cout << "Base's DoFoo1" <<endl;
12.}
13.virtual void DoFoo2(){
14.cout << "Base's DoFoo2" <<endl;
15.}
16.};
17.class Derived: public Base{
18.private:
19.virtual void DoFoo1(){
20.cout << "Derived's DoFoo1" << endl;
21.};
22.};
若不实现接口与实现分离,则从基类到子类都需要修改:
- class Base{
- public:
- virtual void Foo(){
- cout << "Locking" << endl;
- cout << "Base's Foo" << endl;
- cout << "Unlocking" << endl;
- }
- };
- class Derived: public Base{
10.public:
11.virtual void Foo(){
12.cout << "Locking" << endl;
13.cout << "Derived's Foo" << endl;
14.cout << "Unlocking" << endl;
15.};
16.};
注意,当且仅当子类需要调用基类的虚函数时才将虚函数设置为protected(否则没有权限),并且NVI机制不适用于析构函数,对于析构函数, 如果设为公有则应该设置为虚拟(在允许多态删除的基类中),否则设置为私有或者protected的非虚拟形式(不含多态删除的基类中)。
带来的风险:
首先是FBC问题(Fragile Base Class ),下边是一个例子:
- class Set {
- std::set<int> s_;
- public:
- void add (int i) {
- s_.insert (i);
- add_impl (i); // Note virtual call.
- }
- void addAll (int * begin, int * end) {
- s_.insert (begin, end); // --------- (1)
10.addAll_impl (begin, end); // Note virtual call.
11.}
12.private:
13.virtual void add_impl (int i) = 0;
14.virtual void addAll_impl (int * begin, int * end) = 0;
15.};
16.class CountingSet : public Set {
17.private:
18.int count_;
19.virtual void add_impl (int i) {
20.count_++;
21.}
22.virtual void addAll_impl (int * begin, int * end) {
23.count_ += std::distance(begin,end);
24.}
25.};
如果此时我们在父类中修改了addAll函数,改为将从begin到end的数字都调用一遍add函数,那么,子类的功能就紊乱了——子类计数就会 多记录一倍(因为在子类中,add_impl每次都会计数一个,并且addAll_impl也会整体计数一次)。所以,为了防止出现FBC,一般一个公有 非虚函数调用一个私有虚函数。
其次是性能上的考虑,毕竟多了一层函数调用。
3.总结
将NVI机制放在脑子中吧,如果你还是不明白,一个故事化的讲述或许更加合适你。详情可参考http://wenku.it168.com/d_000773510.shtml
转载于:https://www.cnblogs.com/Q685656/archive/2013/01/29/2880871.html
C++程序的设计机制1 NVI机制相关推荐
- Linux并发程序课程设计报告,网络操作系统课程设计--进程机制与并发程序设计-linux下生产者与消费者的问题实现.doc...
网 络 操 作 系 统 课 程 设 计 网络操作系统课程设计 设计内容:进程机制与并发程序设计inux下生产者与消费者的问题实现进程机制与并发程序设计inux下生产者与消费者的问题实现 (1)掌握基本 ...
- 如何设计通用的回调机制
如何设计通用的回调机制 许多程序都需要一种通用的回调机制,这种回调机制不用关心它们的类类型.例如,一个调用GUI组件成员函数的事件驱动的系统中,调用之前并不知道实际的类型信息.这时可以创建一种通用的回 ...
- 苹果IOS,与windows Phone7,系统,内存,CPU处理,及后台程序运行,详解微软墓碑机制的系统...
关于ios的多任务以及内存管理 看了很多人为自己的可用内存是350mb还是380mb纠结.为了多优化出一点可用内存费脑筋. ios的任务管理和内存管理,跟windows是有很大差别的.很多人习惯于用 ...
- 数据传递型情景下事件机制与消息机制的架构设计剖析(目录)
目录 数据传递型情景下事件机制与消息机制的架构设计剖析(一) 转载于:https://www.cnblogs.com/hailan/p/3616766.html
- 【广告算法工程师入门 16】机制设计-最优拍卖机制设计
最优拍卖机制 前文已经介绍到了,如果直接机制(P,M)是激励兼容的,则对所有的竞买人及真实估价vi,其预期支付只与分配规则相关,支付规则决定一个常数项. (注意这里不再要求对称性) 通常情况下售卖者是 ...
- 【广告算法工程师入门 20】机制设计-从GSP机制到VCG机制
机制设计 在前文[广告算法工程师入门 9]机制设计-博弈论基础中已经谈过了微观经济学与博弈论的区别,在微观经济学中市场机制是一个『看不见的手』,调整市场进入均衡状态.在博弈论中,机制设计者(委托人)设 ...
- 【广告算法工程师入门 17】机制设计-有效机制与VCG机制
有效机制 在前文中已经讨论过了,带有保留价的第二价格密封拍卖与最优机制均存在社会效率的损失,不是有效机制. 有效机制是指其分配规则可以最大化社会效率.当只有一个最高价值时,有效分配规则可以把物品分配给 ...
- Effective C++:改善程序与设计的55个具体做法
Effective C++:改善程序与设计的55个具体做法 二.构造/析构/赋值运算 05 Know what functions C++ silently writes and calls. 06 ...
- Qt学习笔记,Qt程序架构设计要旨
Qt学习笔记,Qt程序架构设计要旨 时间过得很快,转眼学习Qt已经有一个多月了,对Qt的学习也在不断的深入中.自己手下的code也很多了,不过不得不说,还有很多的部分没有接触过,比如网络编程,2D,3 ...
- namenode和datanode工作机制_Hadoop的namenode的管理机制,工作机制和datanode的工作原理...
HDFS前言: 1) 设计思想 分而治之:将大文件.大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析: 2)在大数据系统中作用: 为各类分布式运算框架(如:mapr ...
最新文章
- 使用 JavaCSV api 读取和写入 csv 文件
- 东北大学计算机分数线2017,东北大学2017年本科一批录取分数线(全国)
- 13、GridView案例
- 动态规划入门 洛谷P1108 低价购买
- 解决nginx+php二级页面显示空白的问题
- java 获取活动窗口_用Java获取活动窗口信息
- 人人都是 DBA(XII)查询信息收集脚本汇编
- [Windows Phone] 如何在 Windows Phone 应用程式制作市集搜寻
- HDU-4324 Triangle LOVE 拓扑排序
- linux里面的命令
- 搭载Apple芯片的Mac如何使用macOS恢复?
- 计算机等级的判断,计算机等级考试一级WPS判断题及答案
- 计算机版本过低怎么办,浏览器版本过低嗡嗡叫怎么办_电脑显示浏览器版本过低嗡嗡叫如何处理-win7之家...
- 嵌入式培训怎么学?嵌入式开发培训学什么内容
- saltstack(九)returner
- 前端食堂技术周刊第 40 期:HTTP/3、WebContainers 登陆 Firefox、Remix Conf 2022、VueConf US 2022
- 多多视频带货快速出单小技巧!
- 可编译易用的模块化nf-HiPAC移植成功
- AMBA总线---APB总线协议
- v-if和v-show的区别
热门文章
- 保险精算师教你如何用大数据买车
- 【C++】有趣的数字
- mysql交并补_集合交并补运算顺序是什么?
- 基于深度学习智能问答笔记
- 计算机cpu风扇不转怎么办,计算机CPU风扇不转怎么办
- 朱啸虎的“合并盈利论”,实为ofo抢道摩拜带节奏
- 清华大学计算机系刘斌,Tsinghua University Outstanding Master Student 清华大学优秀硕士毕业生...
- Kettle【实践 04】Java环境实现KJB和KTR脚本文件执行v9版本9.0.0.0-423相关依赖说明(云资源分享:依赖包+kjb+ktr+测试源码)
- STM8S自学笔记-001 STM8简介
- 最新机器人视觉系统介绍,给机器人装上“眼睛”