温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

abstract中如何使用class 抽象类

发布时间:2021-07-30 17:44:12 来源:亿速云 阅读:301 作者:Leah 栏目:大数据

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

1. 抽象类的定义

首先来说虚函数;

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

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

纯虚函数的声明有着特殊的语法格式:virtual 返回值类型成员函数名(参数表)=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;

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

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI