使用ostream作为函数参数

时间:2017-08-04 14:31:46

标签: c++ class ostream

我有一个基本的问题,就是要了解ostream究竟是什么。我知道它是输出流的基类,但是在使用它时我不能非常喘息,为什么要使用它而不是仅仅说std :: cout。 所以这里我有这个例子,我必须用pop()函数创建一个名为stack的新类(就像在C ++中已经提供的类一样)。

这里list_node是一个由两个元素组成的结构:键(一个整数)和一个指向下一个整数的指针。

list_node的定义(已经给出):

struct list_node {
int key;
list_node∗ next;
// constructor
list_node (int k, list_node∗ n)
: key (k), next (n) {}
};

以下是该类的定义(已经给出):

class stack {
public:
void push (int value) {...}
...
private:
list_node∗ top_node;
};

这是我遇到问题的部分:

void print (std::ostream& o) const
{
const list_node* p = top_node;
while (p != 0) {
o << p->key << " "; // 1 5 6
p = p->next;
}
}

我不明白为什么他们使用ostream&amp; amp; o作为函数参数。难道他们不能将top_node作为参数并使用它上面的.next函数(.next读取下一个list_node)然后他们可以用std :: cout函数打印它。为什么以他们这样做的方式做得更好?

1 个答案:

答案 0 :(得分:0)

  

为什么以他们这样做的方式做得更好?

我不确定你的问题,也不确定这是一个更好的方法。

也许意图是灵活性。以下是我的应用程序库中的示例:

当我将数据属性声明为ostream

class T431_t
{
   // ...
   std::ostream*      m_so; 
   // ...

我可以简单地使用该属性向'where-m_so-points'发送报告。在这个应用程序中,有几个* mso&lt;&lt; ... 正在使用。这是主要的例子。

inline void reportProgress()
{
    // ...
   *m_so << "  m_blk = " << m_blk
         << "  m_N = 0x" << std::setfill('0') << std::hex << std::setw(16) << m_N
         << "  " << std::dec << std::setfill(' ') << std::setw(3) << durationSec
         << "."  << std::dec << std::setfill('0') << std::setw(3) << durationMSec
         << " sec  (" << std::dec << std::setfill(' ') << std::setw(14)
         << digiComma(m_N) << ")" << std::endl;
   // ...
}

请注意,在类构造函数(ctor)中,m_so有一个默认的赋值给std :: cout。

T431_t(uint64_t maxDuration = MaxSingleCoreMS) :
      // ..
      m_so   (&std::cout), // ctor init - default
      // ..
 {
    // ...

当用户选择双线程处理选项(这是一个命令行选项,通过使用我的桌面的两个处理器在大约1/2的时间内执行应用程序)时,如果我允许,报告将变得难以阅读两个独立的输出流交织在一起(在用户屏幕上)。因此,在由线程2运行的对象实例中,m_so被设置为不同的东西。

以下数据属性捕获并保存线程2输出,以便以后流式传输到std :: cout。

std::stringstream  m_ssMagic; // dual threads use separate out streams

启动线程2并且线程将其设置为私有m_so:

void exec2b ()  //  thread 2 entry
{
    m_now = Clock_t::now();

    m_so = &m_ssMagic; // m_so points to m_ssMagic 

    // ...

    m_ssMagic << "   execDuration =  " << m_ssDuration.str() 
              << " (b)  " << std::endl;
} // exec2b (void)

虽然线程1使用std :: cout,而线程2使用m_ssMagic,但'main'(线程0)只是等待连接。

连接协调线程完成,通常大约在同一时间。 Main(线程0)然后cout是m_ssMagic内容。

//...
// main thread context:
case 2: // one parameter: 2 threads each runs 1/2 of tests
{  // use two new instances
    T431_t  t431a(MaxDualCoreMS); // lower test sequence
    T431_t  t431b(MaxDualCoreMS); // upper test sequence

    // 2 additional threads started here
    std::thread tA (&T431_t::exec2a, &t431a);
    std::thread tB (&T431_t::exec2b, &t431b);

    // 2 join's - thread main (0) waits for each to complete
    tA.join();
    tB.join();

    // tA outputs directly to std::cout
    // tB captured output to T431_t::m_ssMagic. 

    // both thread 1 and 2 have completed, so ok to:
    std::cout << t431b.ssMagicShow() << std::endl;

    retVal = 0;
} break;

完成,这是

std::string ssMagicShow() { return (m_ssMagic.str()); }

摘要

我首先编写了单线程应用程序。在完成这项工作后,我搜索了一种“简单”的方式来使用我桌面上的第二个核心。

作为我的第一个重构的一部分,我a)添加了“std :: ostream m_so”初始化为&amp; std :: cout,并且b)发现了std :: cout的所有用法。其中大多数我只是用“* m_so”代替。然后我c)确认我没有破坏单线程解决方案。非常简单,并且第一次尝试。

后续工作实现了命令行'双线程'选项。

我认为当预算允许时,这种方法将适用于我的下一个桌面。

从OOP的角度来看,这种努力是有效的,因为std :: ostream在std :: cout和std :: stringstream的类层次结构中。因此

 "std::cout is-a std::ostream", 

"std::stringstream is-a std::ostream". 

因此m_so可以指向派生类的实例,并向任一目的地提供虚拟方法'ostream-access'。