BadMondays
BadMondays

Reputation: 21

Scope issue while creating objects inside if statement if C++

This is supposed to be very basic.

Layout:

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();
};

Code:

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

This gives an error:

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

I'm guessing because compiler doesn't know what handler is cause object is created inside an if statement. I need to pick a handler based on a condition, how do I do that?

Obviously this code works:

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

But doesn't look very sexy! Is it really the only way in c++?

Upvotes: 2

Views: 1174

Answers (6)

C. K. Young
C. K. Young

Reputation: 223003

Of course it's not the only way. But you may have to use pointers:

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();
}

(Instead of unique_ptr, you can use boost::scoped_ptr, shared_ptr, and auto_ptr also. But in this case, unique_ptr and boost::scoped_ptr are most appropriate.)

Upvotes: 8

Diego Sevilla
Diego Sevilla

Reputation: 29021

C++ can only do polymorphism in pointers and references. Note that with your code, the actual type of handler is not known till runtime. The only thing known is that it will be of one of the subtypes of handler, so you have to declare a pointer to use the polymorphism:

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();
}

I use std::auto_ptr to assure the pointer will be automatically deleted when the function ends.

Upvotes: 2

Andrei
Andrei

Reputation: 5005

If you go with the pointer approach like the others suggest you should also add a virtual destructor the base class.

This approach can be better expressed using a factory method. Just add a static function in your base class that accepts a connection and returns a (smart) pointer to a handler. Put the "pick" logic there.

If you don't want the pointer approach then the second version you posted is the one to use.

Upvotes: 0

Aleksandar Stojadinovic
Aleksandar Stojadinovic

Reputation: 5049

Declare a pointer somewhere above that code, and then assign an object later in the if statement. Since they are inherited from the same class, OO teaches us that a child can replace a parent :) .

After that it should work.

Just don't forget to destruct! :)

Hope I helped.

Upvotes: 0

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361362

The object handler doesn't exist outside the scope in which its defined.

One solution could be runtime polymorphism, that is, define a base class and a virtual function in it, as:

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
};   

Then use it as:

base_handler *phander ; 
if (connection->http_header.uri_str != "/") {
     phandler = new http_photoserver(connection);
} else {
     phandler = new http_status (connection);
}
phandler->handle();
//...
delete phandler;

Upvotes: 0

Ernest Friedman-Hill
Ernest Friedman-Hill

Reputation: 81684

Use a pointer so you get polymorphic behavior:

auto_ptr<handler> theHandler = (connection->http_header.uri_str != "/") ?
    new http_photoserver(connection) :
    new http_status(connection);
theHandler->handle();

Upvotes: 8

Related Questions