从OpenCV源码学习cpp_virtual
2016-08-24 08:30
176 查看
1. 先丢问题
看cpp源码,发现很多都有类继承树,就是先定义一个抽象基类,再派生,派生,派生。里面稍微复杂的地方,就是virtual关键字。比如这段代码:class RandomTree { public: virtual void split() = 0; void train(){ split(); } }; class AbstractSemanticSegmentationTree : public RandomTree { public: virtual void split(){ cout << "spliting an node in AbstractSemanticSegmentationTree" << endl; } void train(){ RandomTree::train(); } }; class WeightedStdSSF : public AbstractSemanticSegmentationTree { public: }; class StructClassSSF : public AbstractSemanticSegmentationTree { public: virtual void split(){ cout << "spliting an node in StructClassSSF" << endl; } };
2. 分析
这段代码是一棵典型的类继承树,有抽象基类(RandomTree),有派生类。这段代码的用途是,描述随机森林,最后两个派生类分别对应一般随机森林方法和结构化随机森林方法。由此可见,cpp里的多态,对描述算法里的“原算法”,“改进算法”是非常适合的。原算法和改进算法的相同部分,可以写在基类里面,而不同的部分可以分别在派生类里面重载不同的操作。太妙了!!!
2.1 简单例子
class A { public: virtual void foo(){ cout << "A::foo()" << endl; } }; class B : public A { public: void foo(){ cout << "B::foo()" << endl; } }; int main(int argc, char *argv[]) { A *a = new B; a->foo(); return 0; }
这段代码是virtual的典型例子。如果有virtual修饰,a->foo()会调用B的foo(),如果没有,则调用A的foo()。这段代码表明,当使用A *a = new B这种方式实例化对象时,virtual会显现作用。
2.2 分析原例子
使用这个随机森林的实例代码如下:int main(int argc, char *argv[]) { WeightedStdSSF *tree1 = new WeightedStdSSF; tree1->train(); StructClassSSF *tree2 = new StructClassSSF; tree2->train(); return 0; }
tree1的训练会使用AbstractSemanticSegmentationTree的分割函数,而tree2的训练会使用StructClassSSF的分割函数。
能有这种行为的原因是,RandomTree的split()函数是virtual,因此从RandomTree派生的子类和子子类,只要重载了split(),都带上了virtual的标签。这样一来,当需要调用这些split()时,它会搜索最符合要求的那个split()。比如这个例子里,当执行RandomTree::train(),两棵树的训练都需要执行这句话,但是并不是真正的同一句话。
tree1训练中执行的这句话,是在WeightedStdSSF实例化的对象的内存空间里,而tree2训练中执行的这句话,是在StructClassSSF实例化的对象的内存空间里,所以,其实是两句不同的话。
tree1训练,它会把所有split()按照“血缘关系”排序,选其中最亲的执行,tree1会选择AbstractSemanticSegmentationTree中的split()去执行。同理,tree2会选择StructClassSSF的split()去执行。
3. 更多
virtual关键字是对派生类起作用,对当前类没有任何影响。纯虚函数它也是virtual函数,也满足上面说的。只不过,在这基础之上,把本可以基类实现的代码,放在派生类中。这么做目前看来的主要动机是,提供一种类无法被实例化的机制,允许抽象类的存在。(抽象类的意义就在于,维护接口的统一,以及逻辑解耦和,使得接口和实现分开,实现部分的可以修改,而不影响已有的实现)
一旦某个成员函数被修饰了virtual(只有成员函数能够使用virtual),所有这个类派生的所有子类子子类中的重载函数,也都带上了virtual属性。所以,其实AbstractSemanticSegmentationTree和StructClassSSF中的virtual关键字是可以省略的,在功能上并不影响。而一般会注明,是为了时刻提醒程序员,这个成员函数是virtual,提高代码可读性。
相关文章推荐
- 从OpenCV源码学习cpp_explicit
- 从OpenCV源码学习cpp_const
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
- OpenCV学习笔记(29)KAZE 算法原理与源码分析(三)特征检测与描述
- Cocos2d-x学习笔记(17)(TestCpp源码分析-1)
- 学习OpenCV(中文版)PDF及随书源码
- 学习OpenCV的学习笔记系列(二)源码编译及自带样例工程
- OpenCV深入学习(8)--calcHist源码分析
- 学习OpenCV的学习笔记系列(二)源码编译及自带样例工程
- opencv中HOG源码学习笔记
- TLD源码学习-fern.cpp
- opencv学习:模板匹配源码解读
- OpenCV学习笔记(29)KAZE 算法原理与源码分析(三)特征检测与描述
- opencv学习_15 (利用cmake查看opencv的源码)
- OpenCV学习:Mat类详细解析+源码剖析(四)MSize类和Mstep类
- opencv中HOG源码学习笔记
- OpenCV学习笔记(28)KAZE 算法原理与源码分析(二)非线性尺度空间构建
- OpenCV学习:Mat类详细解析+源码剖析(三)遍历矩阵中元素
- OpenCV学习:Mat类详细解析+源码剖析(三)遍历矩阵中元素
- Cocos2d-x学习笔记(19)(TestCpp源码分析-3)