[英]How do I call all functions from sub-classes when they were defined as pure virtual in the super-class?
主要問題是如何實現startTest(),以便它在所有子類中調用runTest。 謝謝!
/*******************
COMPILER TEST
*******************/
class archeTest
{
protected:
short verbosity_;
public:
void setVerbosity(short v)
{
if( ((v == 1) || (v == 0) )
{
verbosity_ = v;
}
else
{
cout << " Verbosity Level Invalid " << endl;
}
}
virtual void runTest() = 0;
{
}
void startTest()
{
}
};
class testNatives : public archeTest
{
public:
void runTest()
{
testInts<short>();
testInts<int>();
testInts<long>();
testInts<unsigned short>();
testInts<unsigned int>();
testInts<unsigned long>();
}
void reportResults() const
{
}
protected:
template<class T> void testFloats()
template<class T> void testInts()
{
verbosity_ = 1;
T failMax;
short passState;
short bitDepth;
const char* a = typeid(T).name();
bool signedType = ((*a == 't') || (*a == 'j') || (*a == 'm'));
/* Bit Depth - Algorithm */
T pow2 = 1, minValue = 0, maxValue = 0, bitCount = 0, failValue = 0;
while(pow2 > 0)
{
pow2 *= 2;
maxValue = pow2-1;
bitCount++;
}
failValue = pow2;
int native1 = bitCount;
int native2 = sizeof(T)*8;
int native3 = numeric_limits<T>::digits;
if( !signedType )
{
native1++;
native3++;
}
if(verbosity_)
{
cout << endl << "**********\n" << reportType(a) << "\n**********" << endl << endl;
cout << "Bit Depth - Algorithm:\t" << native1 << endl;
cout << "Bit Depth - Sizeof:\t" << native2 << endl;
cout << "Bit Depth - File:\t" << native3 << endl;
}
if (native1 == native2 && native1 == native3)
{
cout << "Correlation:\t\tPass" << endl ;
}
else
{
cout << "Correlation:\t\tFail" << endl ;
}
cout << "Max Value:\t\t" << maxValue << endl;
cout << "Max+1 Value:\t\t" << failValue << endl;
}
string reportType(const char* c1)
{
string s1;
switch(*c1)
{
case 't':
s1 = "Unsigned short";
break;
case 'j':
s1 = "Unsigned int";
break;
case 'm':
s1 = "Unsigned long";
break;
case 's':
s1 = "Short";
break;
case 'i':
s1 = "Int";
break;
case 'l':
s1 = "Long";
break;
default:
s1 = "Switch failed";
}
return s1;
}
};
int main()
{
testNatives A;
A.runTest();
}
有可能,但是要做到這一點,您將不得不使用抽象工廠模式。 請閱讀此內容 ,以了解抽象模式是什么以及它如何完成您需要的工作。
如果可以在項目中使用boost,那么可以通過使用boost :: factory template來實現自己的抽象工廠。
如果您不想推出自己的抽象工廠,則可以使用很多其他實現。 這里是一個這樣的實現的鏈接。
編輯:在這種情況下,您還需要一些機制在編譯時向工廠注冊新的測試用例。 這可以通過利用c ++預處理程序或模板來實現。 這是一種使用模板的方法。
好吧,第一重責任原則 。 請記住,您的archeTest
不應管理alle測試對象。 只是讓(一個)著名的Manager
做到這一點!
#include <vector>
class TestManager{
std::vector<archeTest*> _tests;
public:
// either
void AddTest(archeTest* test){
_tests.push_back(test);
}
// OR
archeTest* CreateTest(/*here_be_params*/){
archeTest* test = new archeTest(/*params*/);
// do whatever
_tests.push_back(test);
return test;
}
void RunAllTests() const{
for(int i=0; i < _tests.size(); ++i)
_tests[i]->runTests();
}
// if you create tests in here, you also need to release them at the end
// ONLY do this if your created the tests with CreateTest
// or if you transfer the ownership of the test pointer to TestManager
~TestManager(){
for(int i=0; i < _tests.size(); ++i)
delete _tests[i];
}
};
與運行
TestManager tmgr;
// create all your tests, either with
// archeTest* p = tmgr.CreateTest();
// OR
// archeTest* p = new archeTest();
// tmg.AddTest(p);
// and then run with
tmgr.RunAllTests();
再次,請參閱TestManager
實現中的注釋。
現在,如果您真的不想要額外的類……實際上很簡單,但是有點代碼味道。 只需將archeTest
的構造函數中的類添加到靜態鏈表中,即可解決問題! 當然,銷毀后再將其刪除。 之所以可行,是因為每個派生類xxxstructor都會自動調用基類版本-自身之前的* con *構造函數和自己之后的* de *構造函數:
#include <list>
class archeTest{
private:
typedef std::list<archeTest*> TestList;
static TestList _all_tests;
// to erase the right test on destruction
TestList::iterator _this_test;
public:
archeTest(){
_all_tests.push_back(this);
}
~archeTest(){
_all_tests.erase(_this_test);
}
static void RunAllTests(){
for(TestList::iterator it = _all_tests.begin(); it != _all_tests.end(); ++it)
(*it)->runTests();
}
};
// in some TestManager.cpp
#include "TestManager.h"
TestManager::TestList TestManager::_all_tests;
簡單運行
// create all your tests;
// ...
archeTest::RunAllTests();
由於它是靜態成員函數,因此不需要實例。
請注意,我使用了一個鏈表,因為它使我可以安全地刪除列表中間的測試,而不會使存儲在其他測試對象中的引用無效。
由於許多人發現很難按照我列出的所有帖子進行操作。 我使用boost實現了這個版本。
訣竅在於,當使用派生類定義(新的測試用例)擴展TestTemplate的定義時,由於靜態const的初始化,它會強制調用TestManager :: Register方法。
template<typename TestCase>
const unsigned Test<TestCase>::m_uTestID = TestManager::Register(boost::factory<TestCase*>());
這樣可以確保派生類的構造函數的函子存儲在TestManager的映射中。 現在,在TestManager中,我簡單地遍歷地圖,並使用函子實例化每個Testcase,並在新創建的實例上調用run方法。
從TestTemplate派生的任何類都將自動注冊,無需手動列出所有它們。
#include <map>
#include <iostream>
#include <boost/function.hpp>
#include <boost/functional/factory.hpp>
class ITest {
public:
virtual void run() {
runTest();
}
virtual void runTest() = 0;
};
typedef boost::function< ITest* ()> TestFactory;
class TestManager {
public:
static int Register(TestFactory theFactory) {
std::cout<<"Registering Test Case"<<std::endl;
m_NumTests++;
m_mapAllTests[m_NumTests] = theFactory;
return m_NumTests;
}
void run() {
for(unsigned uTestID = 1; uTestID <= m_NumTests; uTestID++) {
ITest* theTestCase = m_mapAllTests[uTestID]();
theTestCase->run();
delete theTestCase;
}
}
private:
static unsigned m_NumTests;
static std::map<unsigned, TestFactory> m_mapAllTests;
};
unsigned TestManager::m_NumTests = 0;
std::map<unsigned, TestFactory> TestManager::m_mapAllTests;
template<typename TestCase>
class Test : public ITest {
public:
unsigned getID() const {
return m_uTestID;
}
private:
static const unsigned m_uTestID;
};
template<typename TestCase>
const unsigned Test<TestCase>::m_uTestID = TestManager::Register(boost::factory<TestCase*>());
class Test1 : public Test<Test1> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test2 : public Test<Test2> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test3 : public Test<Test3> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test4 : public Test<Test4> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
int main() {
TestManager theManager;
theManager.run();
}
我確實在VS05和VS10上測試了該解決方案。 以下是預期的輸出。
Registering Test Case
Registering Test Case
Registering Test Case
Registering Test Case
Test Id:1
Test Id:2
Test Id:3
Test Id:4
希望它能消除一些混亂。
首先,您將在archeTest中這樣聲明startTest。
virtual void startTest() = 0;
這使其成為必須在子類中實現的純虛函數。 要在子類上調用此方法,必須實例化該特定類的對象。 然后,您可以通過基類指針或指向子類的指針來調用startTest。 請注意,無論哪種情況,指針都必須指向子類的實例化(具體對象)。
您可能想簽出UnitTest ++ (可以在此處瀏覽源代碼 )。 要特別注意TestMacros.h
和CheckMacros.h
, CheckMacros.h
,它們實現了宏來自動收集和運行測試。
例如,以下代碼是“通過UnitTest ++運行失敗測試的最小C ++程序”。
// test.cpp
#include <UnitTest++.h>
TEST(FailSpectacularly)
{
CHECK(false);
}
int main()
{
return UnitTest::RunAllTests();
}
您可以在(簡要的) UnitTest ++概述中閱讀更多內容。 我沒有深入研究如何實現TEST
和CHECK
宏的細節,但是它們確實允許您在許多不同的CPP文件中聲明測試,然后通過對UnitTest::RunAllTests()
的一次調用來運行它們。 也許這已經足夠接近您想要做的事情了?
編輯:沒關系,我的第一個答案沒有任何意義。 在C ++中,您無法獲取類的所有子類的列表以實例化它們,因此我認為您無法以所需的方式實現runTests()。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.