如果这些方法对于子类是唯一的,该如何访问指针的子类的方法?

时间:2019-09-25 21:47:41

标签: c++ pointers subclass c++-standard-library

我的程序的一部分有两种可能的情况:(1)如果用户仅给出2个命令行参数,则从标准输入(cin)中获取输入(2)如果用户给出3个命令行参数(最后一个是文件名),从文件中输入。为了不对这两个选项重复使用相同的代码,我尝试将指向cin和ifstream和istream的超类的指针用于两种输入方式。

我的问题是,在下面的代码的第5和22行上,我试图引用仅可用于子类ifstream(打开和关闭)的方法。根据我的逻辑,如果调用这些方法,则指针必须指向类型ifstream,但是程序无法编译,因为这些方法未在istream类中定义。

有什么办法可以解决这个问题?

istream *currentStream;
    if (argc == 3) {
        // Handle optional file input
        currentStream = new ifstream(argv[2]);
        currentStream->open(argv[2]);
        if (currentStream->fail()) {
            cerr << "FILE COULD NOT BE OPENED\n";
            return 1;
        }
    } else {
        currentStream = &cin;
    }
    string myLine;
    // go line by line and translate it
    while (getline(*currentStream, myLine)) {
        if (currentStream->eof()) {
            break;
        }
        cout << rot13(myLine) << endl;
    }
    if (dynamic_cast<ifstream*>(currentStream)) {
        currentStream->close();
    }
    // handle pointer
    delete currentStream;
    currentStream = NULL;
    return 0;

4 个答案:

答案 0 :(得分:3)

通过获取其缓冲区来动态分配std::cin的“副本”。将内存存储在std::unique_ptr中也是理想的,因为您不必担心手动删除指针。

#include <memory>

int main(int argc, char* argv[]) {
  std::unique_ptr<std::istream> currentStream( argc == 3
    ? std::make_unique<std::ifstream>(argv[2])
    : std::make_unique<std::istream>(std::cin.rdbuf())
  );

  // will only fail when the file cannot open
  if (!currentStream) {
    std::cerr << "FILE COULD NOT BE OPENED\n";
    return 1;
  }

  std::string myLine;
  // go line by line and translate it
  while (std::getline(*currentStream, myLine)) {
    std::cout << rot13(myLine) << std::endl;
  }
}

答案 1 :(得分:1)

可以在几个地方改进您的代码。我认为最突出的改进之处是您试图在一项功能中做太多事情。不重复代码的目标是好的,但是要模块化您的方法。将共享代码移至其自己的功能,如:

void do_stuff(std::istream & currentStream)
{
    std::string myLine;
    // go line by line and translate it
    while (getline(currentStream, myLine)) {
        if (currentStream.eof()) {
            break;
        }
        std::cout << rot13(myLine) << std::endl;
    }
}

此函数应包含两个代码路径之间共享的所有内容。 (我将指针更改为引用,以便调用者立即知道不可以使用null指针。)当您更改主函数以使其调用此函数时,您应该注意到,一些事情变得容易了。特别是,不需要动态分配(这不会导致尝试delete &cin –看起来很糟糕)。您可以随时为文件流使用本地变量。

int main(int argc, const char ** argv)
{
    if (argc == 3) {
        // Handle optional file input
        std::ifstream fileStream(argv[2]);
        fileStream.open(argv[2]);
        if (fileStream.fail()) {
            std::cerr << "FILE COULD NOT BE OPENED\n";
            return 1;
        }
        do_stuff(fileStream);
        fileStream.close();
    } else {
        do_stuff(std::cin);
    }
    return 0;
}

通过将通用代码移至单独的函数,您将可以留在if子句中。无需推断*currentStream是否需要关闭,因为您从未离开过创建文件的代码分支。


在另一个地方,您可以简化事情。不要呼叫openclose。您正在使用带有文件名的ifstream构造函数,因此该构造函数已经为您调用open。 (当您显式调用open时,是在告诉计算机关闭文件并重新打开它。)同样,析构函数将为您调用close;这是RAII的重点。

摆脱不必要的电话离开:

int main(int argc, const char ** argv)
{
    if (argc == 3) {
        // Handle optional file input
        std::ifstream fileStream(argv[2]);
        if (fileStream.fail()) {
            std::cerr << "FILE COULD NOT BE OPENED\n";
            return 1;
        }
        do_stuff(fileStream);
        // Keep in mind that, even though there is no C++ code here, there is something
        // important being done after the call to do_stuff. Specifically, the destructor
        // for fileStream is called, which closes the file for you.
    } else {
        do_stuff(std::cin);
    }
    return 0;
}

答案 2 :(得分:0)

在评论中,Tas使用正确的方法。您不能直接在currentStream上调用该方法,而必须在强制转换接口上调用它。

event

我还认为您应该更改代码以不依赖于动态转换,无论是新接口还是单独的方法。

答案 3 :(得分:0)

只需提取一种方法:

void process(std::istream is) {
    string myLine;
    // go line by line and translate it
    while (getline(is, myLine))
        cout << rot13(myLine) << endl;
}

int main(int argc, char** argv) {
    if (argc == 3) {
        ifstream ifs(argv[2]);
        if (!ifs) {
            cerr << "FILE COULD NOT BE OPENED\n";
            return 1;
        }
        process(ifs);
    } else {
        process(cin);
    }
}