Как правильно назначить cout статической ссылочной переменной ostream?

Я определяю такой класс:

class StaticRuntimeContext {
 public:
  enum Verbosity {
    kHIGH,
    kMEDIUM,
    kLOW,
    kSILENT
  };
  static void Construct();
  static std::ostream& stdout1() {return stdout1_;}
  static std::ostream& stdout2() {return stdout2_;}
  static std::ostream& stdout3() {return stdout3_;}
  static std::ostream& stderr() {return stderr_;}
 protected:
 private:
  static std::ostream& stdout1_;
  static std::ostream& stdout2_;
  static std::ostream& stdout3_;
  static std::ostream& stderr_;
};

Я определяю функцию конструкции как:

void StaticRuntimeContext::Construct() {
  std::ostream& test = cout;
  stdout1_ = cout;
  stdout2_ = cout;
  //stdout3_ = NULL;
  stderr_ = cerr;
}

Я не могу понять, почему назначение cout для тестирования (std::ostream&) нормально для компиляции, но для остальных компилятор выдает сообщения об ошибках, например "stdout1_=cout". Сообщение об ошибке:

/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../include/c++/4.6.2/bits/ios_base.h:791:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private

Мне интересно, что я должен сделать, чтобы правильно назначить cout этим ссылочным переменным ostream. Спасибо!

5 ответов

Решение

Это связано с тем, что ссылки имеют семантику значений, а оператор = копирует объект вместо назначения новой ссылки.

Вместо ссылок вы должны определить статические указатели, назначить их в Construct и вернуть ссылки в ваших методах доступа

  static std::ostream& stdout1() {return *stdout1_;}
  static std::ostream& stdout2() {return *stdout2_;}
  static std::ostream& stdout3() {return *stdout3_;}
  static std::ostream& stderr()  {return *stderr_;}
 protected:
 private:
  static std::ostream* stdout1_;
  static std::ostream* stdout2_;
  static std::ostream* stdout3_;
  static std::ostream* stderr_;

void StaticRuntimeContext::Construct() {
  stdout1_ = &cout;
  stdout2_ = &cout;
  stdout3_ = &cout;
  stderr_ = &cerr;
}

РЕДАКТИРОВАТЬ: И вы должны добавить это в свой файл.cpp

std::ostream* StaticRuntimeContext::stdout1_ = NULL;
std::ostream* StaticRuntimeContext::stdout2_ = NULL;
std::ostream* StaticRuntimeContext::stdout3_ = NULL;
std::ostream* StaticRuntimeContext::stderr_ = NULL;

Этот код

std::ostream& test = cout;

это не задание, а построение новой ссылки. Это также может быть написано

std::ostream& test(cout);

без знака равенства. Эффект тот же.

Ссылка не может быть восстановлена ​​после того, как она создана, поэтому она должна быть установлена ​​на свое значение при создании. Статические члены также должны быть определены где-то, как в соответствующем файле.cpp. Просто установите значения там:

 std::ostream& StaticRuntimeContext::stdout1_ = std::cout;
 std::ostream& StaticRuntimeContext::stdout2_ = std::cout;
 std::ostream& StaticRuntimeContext::stdout3_ = std::clog;
 std::ostream& StaticRuntimeContext::stderr_  = std::cerr;

Вы должны использовать указатель, потому что ссылки не позволяют перепривязывать и std::ostream не копируемый

В C++ ссылочные переменные должны быть инициализированы при их объявлении.

действует:

int x;
int& foo = x;

Недействительным:

int x;
int& foo;
foo = x;

Я не могу понять, почему назначение cout для тестирования (std::ostream&) нормально для компиляции

Потому что это не задание; это инициализация.

Другие вопросы по тегам