C++ (pure)virutal function & abstract class
virtual function
假想我們定義了一個Vehicle
的類別,當中有一個名為go
的成員函數。go
的作用是讓Vehicle
物件向前移動。Vehicle
還有多個子類別,如Boat
,Car
,Plane
。
很顯然地,這三種交通工具向前移動的方式各不相同,在這種情況下,我們可以override(即重定義)父類別Vehicle
裡定義(或宣告)過的函數go
,在Boat
,Car
及Plane
中各自實現相應的前進方式。
到了這裡,可能還看不出虛擬函數的作用。現在假想我們有一個Vehicle
類別的指標,它可能會動態地指向Boat
,Car
或Plane
。
如果我們不使用虛擬函數,那麼C++就無法在執行時判斷指標指向的物件是屬於哪個子類別的,它只能依據指標的類別(即Vehicle
)調用相應的go
函數(即Vehicle::go
)。
反之,如果我們將Vehicle::go
宣告為虛擬函數,C++就能在執行時正確地解析出指標所指向的物件是屬於哪個子類別,進而調用該子類別override的函數(即Boat::go
,Car::go
或Plane::go
),這個就是所謂的runtime polymorphism,late binding。
在TensorRT/samples/common/logging.h
中定義了Logger
的成員函數log
:
class Logger : public nvinfer1::ILogger
{
public:
//...
void log(Severity severity, const char* msg) override
{
//LogStreamConsumer是std::ostream的子類別
LogStreamConsumer(mReportableSeverity, severity) << "[TRT] " << std::string(msg) << std::endl;
}
//...
};
這裡使用了一個關鍵字override
,根據Is the ‘override’ keyword just a check for a overridden virtual method?,這只是一種保護機制,確保子類別Logger
的函數log
有正確地override其父類別nvinfer1::ILogger
的函數log
,而非又重新定義了另外一個函數。
Logger
的父類別nvinfer1::ILogger
定義於TensorRT/include/NvInferRuntimeCommon.h
:
namespace nvinfer1
{
class ILogger
{
public:
//...
virtual void log(Severity severity, const char* msg) TRTNOEXCEPT = 0;
};
//...
}
上面的代碼中在函數宣告結尾加上了=0
,這代表nvinfer1::ILogger::log
是一個"純虛擬函數",只做宣告,不包含任何定義。
因為nvinfer1::ILogger
包含了至少一個純虛擬函數,所以我們可以說它是抽象類別(abstract class)。
參考連結
Pure Virtual Functions and Abstract Classes in C++
Is the ‘override’ keyword just a check for a overridden virtual method?