从OpenCV源码学习cpp_virtual

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. 更多

  1. virtual关键字是对派生类起作用,对当前类没有任何影响。
  2. 纯虚函数它也是virtual函数,也满足上面说的。只不过,在这基础之上,把本可以基类实现的代码,放在派生类中。这么做目前看来的主要动机是,提供一种类无法被实例化的机制,允许抽象类的存在。(抽象类的意义就在于,维护接口的统一,以及逻辑解耦和,使得接口和实现分开,实现部分的可以修改,而不影响已有的实现)
  3. 一旦某个成员函数被修饰了virtual(只有成员函数能够使用virtual),所有这个类派生的所有子类子子类中的重载函数,也都带上了virtual属性。所以,其实AbstractSemanticSegmentationTree和StructClassSSF中的virtual关键字是可以省略的,在功能上并不影响。而一般会注明,是为了时刻提醒程序员,这个成员函数是virtual,提高代码可读性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值