您好,登錄后才能下訂單哦!
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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。