簡體   English   中英

當子類中的所有函數在超類中定義為純虛函數時,如何調用它們?

[英]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.hCheckMacros.hCheckMacros.h ,它們實現了宏來自動收集和運行測試。

例如,以下代碼是“通過UnitTest ++運行失敗測試的最小C ++程序”。

// test.cpp
#include <UnitTest++.h>

TEST(FailSpectacularly)
{
    CHECK(false);
}

int main()
{
    return UnitTest::RunAllTests();
}

您可以在(簡要的) UnitTest ++概述中閱讀更多內容。 我沒有深入研究如何實現TESTCHECK宏的細節,但是它們確實允許您在許多不同的CPP文件中聲明測試,然后通過對UnitTest::RunAllTests()的一次調用來運行它們。 也許這已經足夠接近您想要做的事情了?

編輯:沒關系,我的第一個答案沒有任何意義。 在C ++中,您無法獲取類的所有子類的列表以實例化它們,因此我認為您無法以所需的方式實現runTests()。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM