abstract class 抽象类的使用

目录

1. 抽象类的定义

2. 在ORBSLAM3中的使用

3. 编译报错


ORBSLAM3中使用了抽象类,整理代码的时候发现在抽象类的使用中,还有很多的问题,借此机会总结一下。

1. 抽象类的定义

首先来说虚函数;

虚函数是在基类中被声明为virtual的函数, 将一个有实现的函数设定为虚函数, 可以方便基类对其进行调用, 可实现函数的动态重载;

动态重载也就是在可以依据后期的传入类的类型,选择具体的实现函数;

virtual是虚函数的标准; 

如果在一个类中声明纯虚函数, 则在虚函数后面加 = 0 标志; 因此纯虚函数的声明有着特殊的语法格式:virtual 返回值类型成员函数名(参数表)=0;

包含有纯虚函数是成为抽象类的充要条件;

纯虚函数明显的特征是 他必须在继承类中重新声明, 并且不能加 =0,否则就依然不能被实例化;

包含了纯虚函数的类被称为抽象类,抽象类中可以有纯虚函数,也可以有其他非虚函数;因为抽象类中都是没有定义的纯虚函数,因此不能定义对象;

在C++中,我们可以把只能用于被继承而不能直接创建对象的类设置为抽象类(Abstract Class)。

举一个小栗子~~

比如我今天想写一个代码,可以自动帮我炒肉菜,我需要实现的效果是,如果传入鸡肉,则做宫保鸡丁;如果传入排骨,则做土豆炖排骨;如果传入牛肉,则做成黑椒牛仔骨;每次 只做一道菜;

因为无法预料到具体使用时可能会传入的肉的类型,总不能三个对象都创建?这个时候可以创建抽象类 肉类;以及派生类 鸡肉,排骨,和牛肉

这三个类中都需要有对应做菜的函数,如cook();

#include<iostream>
using namespace std;
class Meat   //抽象类:肉类
{
public:
    virtual void cook()=0;//纯虚函数
};

class Chicken:public Meat //派生类:鸡肉
{
public:
    void cook(){
        cout<<"热锅下油,加入黄瓜丁和胡萝卜丁翻炒至半熟,划入鸡丁翻炒,最后放入买好的宫保鸡丁酱和花生米即可"<endl;
    }
};

class Rib:public Meat{ //派生类:排骨
public:
    void cook(){
        cout<<"热锅下油,排骨炒至半熟,放入土豆块翻炒,加水收汁即可"<<endl;
    }
};

class Beef:public Meat{ //派生类:牛肉
public:
    void cook(){
        cout<<"热锅下油,洋葱炒香,加入牛仔骨和黑椒酱,加水收汁即可"<<endl;
    }
};

int main()
{
    Meat *realmeat; //定义对象指针数组
    std::string mymeat = "Chicken";
    if(mymeat == ""){
      realmeat = new Chicken();
    }else if(mymeat == "Rib"){
      realmeat = new Rib();;
    } else if (mymeat == "Beef"){
      realmeat = new Beef();
    }
    realmeet->cook();
    return 0;

}

大概的一个例子,不知道有没有解释清楚,有问题欢迎指正,在上面的例子中也能看到,抽象类是不能创建对象的,但是可以定义指针指向抽象类

抽象类的规定

(1)抽象类只能用作其他类的基类,不能建立抽象类对象。

(2)抽象类不能用作参数类型、函数返回类型或显式转换的类型。

(3)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。

2. 在ORBSLAM3中的使用

在ORBSLAM3中的使用,也说明了抽象类存在的意义,也就是实现了多态;可以把它理解成一个操作接口,具体的实现在派生类中;

ORBSLAM3中因为新加入了KB模型,这就导致无法在最一开始后时候确定相机的类型,是普通针孔相机(Pinhole) 还是鱼眼相机(使用KB);

如果不使用抽象类的话,以单目相机为例,除了需要为Pinhole和KB各自创建一个类,同时在需要使用相机参数的时候,定义两个对象,一个Pinhole,一个KB;

然后,在使用时,只使用其中的一个;

有了抽象类,就可以先将相机的模型声明成一个抽象的类型:GeometricCamera* mpCamera;然后按照配置文件中的输入是Pinhole还是KannalaBrandt8, 定义对象mpCamera即可;如:

mpCamera = new Pinhole(vCamCalib); //或者
mpCamera = new KannalaBrandt8(vCamCalib);

同时,因为模型不同,不同坐标系之间的转换函数也会不同,以投影函数为例:

首先在抽象类中定义一个虚函数:

virtual cv::Point2f project(const cv::Point3f &p3D) = 0;

然后具体的实现时, 在KB模型中为

    cv::Point2f KannalaBrandt8::project(const cv::Point3f &p3D) {
        const float x2_plus_y2 = p3D.x * p3D.x + p3D.y * p3D.y;
        const float theta = atan2f(sqrtf(x2_plus_y2), p3D.z);
        const float psi = atan2f(p3D.y, p3D.x);

        const float theta2 = theta * theta;
        const float theta3 = theta * theta2;
        const float theta5 = theta3 * theta2;
        const float theta7 = theta5 * theta2;
        const float theta9 = theta7 * theta2;
        const float r = theta + mvParameters[4] * theta3 + mvParameters[5] * theta5
                        + mvParameters[6] * theta7 + mvParameters[7] * theta9;

        return cv::Point2f(mvParameters[0] * r * cos(psi) + mvParameters[2],
                           mvParameters[1] * r * sin(psi) + mvParameters[3]);

    }

在Pinhole中为:

    cv::Point2f Pinhole::project(const cv::Point3f &p3D) {
        return cv::Point2f(mvParameters[0] * p3D.x / p3D.z + mvParameters[2],
                           mvParameters[1] * p3D.y / p3D.z + mvParameters[3]);
    }

使用时按照传入相机的类型,mpCamera->project(p3D) 代码会根据相机的类型自动调用对应的实现函数;

3. 编译报错

  a.  invalid new-expression of abstract class type ‘×××ב

这种情况一般是抽象类中的虚函数,并没有在派生类中被实现,也就是派生类中没有定义;一般编译的时候会指示出具体的问题出处,如下面:

src/Tracking.cc: In member function ‘bool ORB_SLAM2::Tracking::ParseCamParamFile(cv::FileStorage&)’:
src/Tracking.cc:169:34: error: invalid new-expression of abstract class type ‘ORB_SLAM2::EUCM’
     mpCamera = new EUCM(vCamCalib);
                                  ^
In file included from src/Tracking.cc:28:0:
/include/CameraModels/EUCM.h:12:7: note:   because the following virtual functions are pure within ‘ORB_SLAM2::EUCM’:
 class EUCM final : public GeometricCamera{
       ^
In file included from include/Tracking.h:30:0,
                 from src/Tracking.cc:21:
include/CameraModels/GeometricCamera.h:38:29: note: 	virtual cv::Point2f ORB_SLAM2::GeometricCamera::Camera2Img(const cv::Mat&)
         virtual cv::Point2f Camera2Img(const cv::Mat& m3D) = 0;

指出了抽象类中的Camera2Img() 在派生类EUCM中没有对应的实现,而其实我这里有对应的函数,但是形参类型写错了;

b. C++ : Cannot declare field to be of abstract type

这里是抽象类的实例化问题,也就是上面说到的,抽象类并不能定义对象,但是可以定义指向抽象类的指针;上面炒菜的例子中,如果我定义:

 Meat realmeat;

就会出现类似的报错,但是定义

 Meat *realmeat;

则正确;

REF:

抽象类的定义和说明

Cannot declare field to be of abstract type

虚函数与纯虚函数以及抽象类-菜鸟教程

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值