abstract中如何使用class 抽象类,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
首先来说虚函数;
虚函数是在基类中被声明为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)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。
在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) 代码会根据相机的类型自动调用对应的实现函数;
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 抽象类的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。