2014-09-26 28 views
1

在模板類中,我試圖從使用dynamic_cast從文件讀取的字符串進行強制轉換,並希望能夠使用bad_cast異常捕獲失敗的強制轉換。然而,編譯時(與測試程序中設置雙象模板類,我得到這個錯誤的dynamic_cast:dynamic_cast帶有模板類「dynamic_cast的無效目標類型」

datafilereader.cpp(20): error C2680: 'double *' : invalid target type for dynamic_cast 

我試圖寫它的作爲只是<T>代替<T*>(後者似乎是共同的這樣,當我瞭解到了動態轉換...),但幾乎同樣的錯誤等問題。

DataFileReader.cpp

#include "DataFileReader.h" 
#include <typeinfo> 

template <typename T> 
void DataFileReader<T>::openFiles() { 
    dataFileStream.open(dataFileName); 
    errorFileStream.open(errorFileName, ios::app); 
    if (!(dataFileStream.is_open() && errorFileStream.is_open())) 
      throw(runtime_error("Couldn't open at least one of the files.")); 
} 

template <typename T> 
bool DataFileReader<T>::readNextValue(T &aValue) { 
    ios_base::iostate mask = ios::eofbit|ios::failbit|ios::badbit; 
    dataFileStream.exceptions(mask); 
    while (true) { 
     string readValue; 
     try { 
      dataFileStream >> readValue; 
      aValue = dynamic_cast<T*>(readValue); 
      return true; 
     } 
     catch(bad_cast &bc) { 
      errorFileStream << readValue << " - " << bc.what() << endl; 
     } 
     catch(ios_base::failure &eo) { 
      if(dataFileStream.eof()) 
       return false; 
     } 
    } 
} 

DataFileReader.h

#ifndef DataFileReader_H 
#define DataFileReader_H 

#include <string> 
#include <iostream> 
#include <fstream> 

using namespace std; 

template <typename T> 
class DataFileReader { 

    private: 
     string dataFileName; 
     string errorFileName; 
     ifstream& dataFileStream; 
     ofstream& errorFileStream; 

    public: 
     DataFileReader(string aDataFileName, string aErrorFileName): dataFileName(aDataFileName), errorFileName(aErrorFileName), dataFileStream(*(new std::ifstream(""))), errorFileStream(*(new std::ofstream(""))) {}; 
     /* pre: A file named aDataFile contains values to read. */ 
     ~DataFileReader() {dataFileStream.close(); errorFileStream.close(); delete dataFileStream; delete errorFileStream;} 
     /* post: Files are closed */ 
     void openFiles(); // throw (runtime_error); 
     /* post: An input stream from the file named aDataFile and an output stream to the file named aErrorFile are opened. 
     If either of these operations fails a runtime_error exception is thrown. */ 
     bool readNextValue(T &aValue); 
     /* pre: openFiles has been successfully called. 
     post: If a value has been successfully read, aValue holds that value and true is returned. 
     Else, the read operation encountered an end-of-file and false is returned. */ 
}; 

#endif 

DataTestClass.cpp

#ifndef DataTestClass_H 
#define DataTestClass_H 

#include "DataFilter.cpp" 
#include "DataFileReader.cpp" 
#include <iostream> 
#include <fstream> 
#include <string> 
#include <exception> 
#include <vector> 

//--------------------------------------------------------------------------- 

vector<double> vec; 
int rangeErrorCounter = 0; 

void printResults() { 
    double summa(0), medel(0); 
    vector<double>::iterator first, last, it; 
    first = vec.begin(); 
    last = vec.end(); 
    for (it = first; it != last; ++it) 
     summa += *it; 
    medel = summa/vec.size(); 

    cout << "Lästa numeriska värden:\t" << vec.size()+rangeErrorCounter << endl; 
    cout << "Värden utanför intervallet:\t" << rangeErrorCounter << endl; 
    cout << "Summa:\t\t\t" << summa << endl; 
    cout << "Medelvärde:\t\t" << medel << endl; 
} 

int main(int args[]) 
{ 
    DataFileReader<double> dr("Values.dat", "ReadErrors.dat"); 

    try { 
     dr.openFiles(); 
    } 
    catch (runtime_error &rt) { 
     cout << "Error reading files: " << rt.what() << endl; 
     return 0; 
    } 

    DataFilter<double> df(&dr, 0.0, 10.0); 
    ofstream os("RangeErrors.dat"); 

    if(os.is_open()) 
     while(true) { 
      double value; 
      try { 
       while(df.getNextValue(value)) 
        vec.push_back(value); 
       printResults(); 
       os.close(); 
       return 0; 
      } 
      catch(range_error) { 
       rangeErrorCounter++; 
       os << value << endl; 
      } 
     } 
    else 
     cout << "Couldn't open RangeErrors.dat" << endl; 
} 

#endif 

DataFilter.cpp

#include "DataFilter.h" 

template <typename T> 
bool DataFilter<T>::getNextValue(T &aValue) { 
    if (fileReader.readNextValue(aValue)) { 
     if (aValue > max || aValue < min) 
      throw(range_error("Outside of range")); 
     return true; 
    } 
    return false; 
} 

DataFilter.h

#ifndef DataFilter_H 
#define DataFilter_H 
#include "DataFileReader.h" 

template <typename T> 
class DataFilter { 

    private: 
     DataFileReader<T> fileReader; 
     T min, max; 

    public: 
     DataFilter(DataFileReader<T> *aReader, T aMin, T aMax): fileReader(*aReader), min(aMin), max(aMax) {}; 
     /* pre: aReader points to an instance of DataFileReader<T> for which openFiles() has been succesfully called. */ 
     bool getNextValue(T &aValue); // throw (range_error); 
     /* pre: an earlier call to getNextValue() has not returned false. 
     post: true is returned if aValue holds a value read from aReader. If a value could not be read, false is returned. 
     If a value is read but is not within the interval specified by aMin and aMax parameters to the constructor, a range_error exception is thrown. */ 
}; 

#endif 

得到任何幫助。經過幾個小時搜索SO和Google後,我仍然難倒...

+0

你似乎誤解了'dynamic_cast'。它意味着將指針(或引用)通用到基類或派生類。 – 2014-09-26 02:28:14

+0

您可能對['boost :: lexical_cast']感興趣(http://www.boost.org/doc/libs/1_56_0/doc/html/boost_lexical_cast.html) – Oktalist 2014-09-26 15:03:50

+0

「我試圖從一個字符串使用dynamic_cast從文件中讀取...「 - *爲什麼*你想要這樣做? 'dynamic_cast'具有定義良好的特定功能。它不會做任何事情,甚至會遠遠滿足你所要求的。 'dynamic_cast'可以應用於'string'對象,絕對沒有意義。 – AnT 2014-09-26 15:05:32

回答

5

您不能使用dynamic_caststring變量轉換爲不是從string派生的數據類型。這樣做是編譯時錯誤,你不能在運行時捕獲它。

如果你想解析string值轉換成不同的類型,使用istringstream,如:

if (!(dataFileStream >> readValue)) // did I/O fail? 
    return false; 
istringstream iss(readValue); 
if (!(iss >> aValue)) // did parsing fail? 
    return false; 
return iss.eof(); // was the entire value consumed? 
+0

謝謝雷米。如果在這種情況下無法完成double轉換(比如讀取的字符串同時包含數字和字母),istringstream會以某種方式顯示它(異常?)?因爲我需要捕捉任何不可轉換的條目以不同的方式使用這些條目。 – SwedishGit 2014-09-26 03:00:37

+0

假設'readValue'是'「123abc」'。使用'istringstream',讀取double會返回'123'。你可以使用'eof()'來說明這一點。 – 2014-09-26 15:05:00

+0

@Matt McNabb:不,它不會。首先,'dynamic_cast'只能轉換爲指針和引用類型。在轉換爲指針類型時,參數也必須是一個指針。其次,如果目標類是從'std :: string'派生的,那麼'dynamic_cast'就是* downcast *。 Downcast需要多態類型作爲源。但'std :: string'不是多態的。 – AnT 2014-09-26 15:09:59