C++程序的设计机制1 NVI机制

我们都知道在C++程序设计中,存在一些设计开发的机制。本文主要介绍其中的NVI机制,也就是Non-Virtual Interface,希望对你有帮助,一起来看。

AD:

C++的程序设计中有一些设计开发的典型机制需要整理讨论,在此抛砖引玉,为自己做积累,请高人也多多指教。

1.简介

在标准C++库中我们可以看到这样的一个现象:

6个公有虚函数,并且都是std::exception::what()和其重载。

142个非公有虚函数。

这样设计的目的何在呢,为什么“多此一举”的把虚函数设置为非公有呢?

这就是NVI机制要求的:将虚函数声明为非公有,而将公有函数都声明为非虚——虚拟和公有选其一。

2.机制分析

程序员常常将基类中的虚函数公有化,来提供一个接口的定义(virtual的功劳)同时提供其实现(具体的一个实现)。

  1. class Base{
  2. public:
  3. virtual void Foo(int){
  4. cout<< "Base's Foo!" << endl;
  5. };
  6. };

问题就出在“同时”——一个定义了接口的形式,一个定义了默认的一个实现,显然这样的设计没有将接口定义和实现分来。在这个时候,我们可以使用模板方法模式的思想:

  1. class Base{
  2. public:
  3. void Foo(){
  4. DoFoo1();
  5. DoFoo2();
  6. }//use DoFooX()
  7. private:
  8. virtual void DoFoo1(){
  9. 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)的加锁解锁控制:

若我们完成这样的接口与实现分离,那么我们的实现是在基类的接口处添加所需流程即可,子类不需要修改:

  1. class Base{
  2. public:
  3. void Foo(){
  4. cout << "Locking" << endl;
  5. DoFoo1();
  6. DoFoo2();
  7. cout << "Unlocking" << endl;
  8. }//use DoFooX()
  9. 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.};

若不实现接口与实现分离,则从基类到子类都需要修改:

  1. class Base{
  2. public:
  3. virtual void Foo(){
  4. cout << "Locking" << endl;
  5. cout << "Base's Foo" << endl;
  6. cout << "Unlocking" << endl;
  7. }
  8. };
  9. 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 ),下边是一个例子:

  1. class Set {
  2. std::set<int> s_;
  3. public:
  4. void add (int i) {
  5. s_.insert (i);
  6. add_impl (i); // Note virtual call.
  7. }
  8. void addAll (int * begin, int * end) {
  9. 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机制相关推荐

  1. Linux并发程序课程设计报告,网络操作系统课程设计--进程机制与并发程序设计-linux下生产者与消费者的问题实现.doc...

    网 络 操 作 系 统 课 程 设 计 网络操作系统课程设计 设计内容:进程机制与并发程序设计inux下生产者与消费者的问题实现进程机制与并发程序设计inux下生产者与消费者的问题实现 (1)掌握基本 ...

  2. 如何设计通用的回调机制

    如何设计通用的回调机制 许多程序都需要一种通用的回调机制,这种回调机制不用关心它们的类类型.例如,一个调用GUI组件成员函数的事件驱动的系统中,调用之前并不知道实际的类型信息.这时可以创建一种通用的回 ...

  3. 苹果IOS,与windows Phone7,系统,内存,CPU处理,及后台程序运行,详解微软墓碑机制的系统...

    关于ios的多任务以及内存管理 看了很多人为自己的可用内存是350mb还是380mb纠结.为了多优化出一点可用内存费脑筋. ios的任务管理和内存管理,跟windows是有很大差别的.很多人习惯于用  ...

  4. 数据传递型情景下事件机制与消息机制的架构设计剖析(目录)

    目录 数据传递型情景下事件机制与消息机制的架构设计剖析(一) 转载于:https://www.cnblogs.com/hailan/p/3616766.html

  5. 【广告算法工程师入门 16】机制设计-最优拍卖机制设计

    最优拍卖机制 前文已经介绍到了,如果直接机制(P,M)是激励兼容的,则对所有的竞买人及真实估价vi,其预期支付只与分配规则相关,支付规则决定一个常数项. (注意这里不再要求对称性) 通常情况下售卖者是 ...

  6. 【广告算法工程师入门 20】机制设计-从GSP机制到VCG机制

    机制设计 在前文[广告算法工程师入门 9]机制设计-博弈论基础中已经谈过了微观经济学与博弈论的区别,在微观经济学中市场机制是一个『看不见的手』,调整市场进入均衡状态.在博弈论中,机制设计者(委托人)设 ...

  7. 【广告算法工程师入门 17】机制设计-有效机制与VCG机制

    有效机制 在前文中已经讨论过了,带有保留价的第二价格密封拍卖与最优机制均存在社会效率的损失,不是有效机制. 有效机制是指其分配规则可以最大化社会效率.当只有一个最高价值时,有效分配规则可以把物品分配给 ...

  8. Effective C++:改善程序与设计的55个具体做法

    Effective C++:改善程序与设计的55个具体做法 二.构造/析构/赋值运算 05 Know what functions C++ silently writes and calls. 06 ...

  9. Qt学习笔记,Qt程序架构设计要旨

    Qt学习笔记,Qt程序架构设计要旨 时间过得很快,转眼学习Qt已经有一个多月了,对Qt的学习也在不断的深入中.自己手下的code也很多了,不过不得不说,还有很多的部分没有接触过,比如网络编程,2D,3 ...

  10. namenode和datanode工作机制_Hadoop的namenode的管理机制,工作机制和datanode的工作原理...

    HDFS前言: 1) 设计思想 分而治之:将大文件.大批量文件,分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析: 2)在大数据系统中作用: 为各类分布式运算框架(如:mapr ...

最新文章

  1. 使用 JavaCSV api 读取和写入 csv 文件
  2. 东北大学计算机分数线2017,东北大学2017年本科一批录取分数线(全国)
  3. 13、GridView案例
  4. 动态规划入门 洛谷P1108 低价购买
  5. 解决nginx+php二级页面显示空白的问题
  6. java 获取活动窗口_用Java获取活动窗口信息
  7. 人人都是 DBA(XII)查询信息收集脚本汇编
  8. [Windows Phone] 如何在 Windows Phone 应用程式制作市集搜寻
  9. HDU-4324 Triangle LOVE 拓扑排序
  10. linux里面的命令
  11. 搭载Apple芯片的Mac如何使用macOS恢复?
  12. 计算机等级的判断,计算机等级考试一级WPS判断题及答案
  13. 计算机版本过低怎么办,浏览器版本过低嗡嗡叫怎么办_电脑显示浏览器版本过低嗡嗡叫如何处理-win7之家...
  14. 嵌入式培训怎么学?嵌入式开发培训学什么内容
  15. saltstack(九)returner
  16. 前端食堂技术周刊第 40 期:HTTP/3、WebContainers 登陆 Firefox、Remix Conf 2022、VueConf US 2022
  17. 多多视频带货快速出单小技巧!
  18. 可编译易用的模块化nf-HiPAC移植成功
  19. AMBA总线---APB总线协议
  20. v-if和v-show的区别

热门文章

  1. 保险精算师教你如何用大数据买车
  2. 【C++】有趣的数字
  3. mysql交并补_集合交并补运算顺序是什么?
  4. 基于深度学习智能问答笔记
  5. 计算机cpu风扇不转怎么办,计算机CPU风扇不转怎么办
  6. 朱啸虎的“合并盈利论”,实为ofo抢道摩拜带节奏
  7. 清华大学计算机系刘斌,Tsinghua University Outstanding Master Student 清华大学优秀硕士毕业生...
  8. Kettle【实践 04】Java环境实现KJB和KTR脚本文件执行v9版本9.0.0.0-423相关依赖说明(云资源分享:依赖包+kjb+ktr+测试源码)
  9. STM8S自学笔记-001 STM8简介
  10. 最新机器人视觉系统介绍,给机器人装上“眼睛”