Проблема при создании объектов внутри оператора if в C ++ - PullRequest
2 голосов
/ 13 июня 2011

Это должно быть очень просто.

Макет:

class handler {
    public:
        handler(Connection *conn) { connection = conn; }
        virtual void handle() = 0;
};

class http_status : public handler {
    public:
        http_status(Connection *conn) : handler(conn) { }
        void handle();
};

class http_photoserver : public handler {
    public:
        http_photoserver(Connection *conn) : handler(conn) { }
        void handle();
};

Код:

void pick_and_handle() {
  if (connection->http_header.uri_str != "/") {
     http_photoserver handler(connection);
  } else {
     http_status handler(connection);
  }
  handler.handle();
}

Это дает ошибку:

../handler.cpp:51:10: error: expected unqualified-id before ‘.’ token

Я предполагаю, потому что компилятор не знает, что такое обработчик, потому что объект создается внутри оператора if.Мне нужно выбрать обработчик на основе условия, как мне это сделать?

Очевидно, этот код работает:

  if (connection->http_header.uri_str != "/") {
     http_photoserver handler(connection);
     handler.handle();
  } else {
     http_status handler(connection);
     handler.handle();
  }

Но выглядит не очень сексуально!Это действительно единственный способ в C ++?

Ответы [ 6 ]

8 голосов
/ 13 июня 2011

Используйте указатель, чтобы получить полиморфное поведение:

auto_ptr<handler> theHandler = (connection->http_header.uri_str != "/") ?
    new http_photoserver(connection) :
    new http_status(connection);
theHandler->handle();
8 голосов
/ 13 июня 2011

Конечно, это не единственный способ.Но вам, возможно, придется использовать указатели:

void pick_and_handle() {
    unique_ptr<handler> http_handler;
    if (connection->http_header.uri_str != "/")
        http_handler.reset(new http_photoserver(connection));
    else
        http_handler.reset(new http_status(connection));
    http_handler->handle();
}

(Вместо unique_ptr вы также можете использовать boost::scoped_ptr, shared_ptr и auto_ptr. Но в этом случае unique_ptrboost::scoped_ptr являются наиболее подходящими.)

2 голосов
/ 13 июня 2011

C ++ может делать полиморфизм только в указателях и ссылках.Обратите внимание, что с вашим кодом фактический тип handler неизвестен до времени выполнения.Известно лишь то, что это будет один из подтипов handler, поэтому вы должны объявить указатель для использования полиморфизма:

void pick_and_handle() {
  std::auto_ptr<handler> h;
  if (connection->http_header.uri_str != "/") {
     h.reset(new http_photoserver(connection));
  } else {
     h.reset(new http_status(connection));
  }
  h->handle();
}

Я использую std::auto_ptr, чтобы убедиться,автоматически удаляется при завершении функции.

0 голосов
/ 13 июня 2011

Если вы придерживаетесь указателя, как другие предлагают добавить виртуальный деструктор в базовый класс.

Этот подход можно лучше выразить с помощью фабричного метода.Просто добавьте статическую функцию в ваш базовый класс, которая принимает connection и возвращает (умный) указатель на handler.Поместите туда логику «выбора».

Если вы не хотите использовать указатель, тогда вы должны использовать вторую версию, которую вы разместили.

0 голосов
/ 13 июня 2011

Объявите указатель где-то выше этого кода, а затем назначьте объект позже в операторе if. Поскольку они унаследованы от одного класса, ОО учит нас, что ребенок может заменить родителя :).

После этого должно работать.

Только не забудь уничтожить! :)

Надеюсь, я помог.

0 голосов
/ 13 июня 2011

Объект handler не существует вне области, в которой он определен.

Одним из решений может быть полиморфизм времени выполнения, то есть определение базового класса и виртуальной функции в нем, как:

struct base_handler
{
   virtual void handle(Connection *conn) = 0;   //interface
   virtual ~base_handler() {}  //must make it virtual!
};
struct http_photoserver  : base_handler
{
     virtual void handle(Connection *conn)  {}  //implementation
};
struct http_status : base_handler
{
     virtual void handle(Connection *conn)  {}  //implementation
};   

Затем используйте его как:

base_handler *phander ; 
if (connection->http_header.uri_str != "/") {
     phandler = new http_photoserver(connection);
} else {
     phandler = new http_status (connection);
}
phandler->handle();
//...
delete phandler;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...