千家信息网

abstract中如何使用class 抽象类

发表于:2024-11-22 作者:千家信息网编辑
千家信息网最后更新 2024年11月22日,abstract中如何使用class 抽象类,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1. 抽象类的定义首先来说虚函数;虚函数是在基
千家信息网最后更新 2024年11月22日abstract中如何使用class 抽象类

abstract中如何使用class 抽象类,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

1. 抽象类的定义

首先来说虚函数;

虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现函数的动态重载;

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

纯虚函数的声明有着特殊的语法格式:virtual 返回值类型成员函数名(参数表)=0;

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

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

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

举一个小栗子~~

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

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

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

#includeusing namespace std;class Meat   //抽象类:肉类{public:    virtual void cook()=0;//纯虚函数};class Chicken:public Meat //派生类:鸡肉{public:    void cook(){        cout<<"热锅下油,加入黄瓜丁和胡萝卜丁翻炒至半熟,划入鸡丁翻炒,最后放入买好的宫保鸡丁酱和花生米即可"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;

看完上述内容,你们掌握abstract中如何使用class 抽象类的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

0