views:

165

answers:

3

I took the following code from the examples page on Asio

    class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
  typedef boost::shared_ptr<tcp_connection> pointer;

  static pointer create(boost::asio::io_service& io_service)
  {
    return pointer(new tcp_connection(io_service));
  }

  tcp::socket& socket()
  {
    return socket_;
  }

  void start()
  {
    message_ = make_daytime_string();

    boost::asio::async_write(socket_, boost::asio::buffer(message_),
        boost::bind(&tcp_connection::handle_write, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

private:
  tcp_connection(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  void handle_write(const boost::system::error_code& /*error*/,
      size_t /*bytes_transferred*/)
  {
  }

  tcp::socket socket_;
  std::string message_;
};

I'm relatively new to C++ (from a C# background), and from what I understand, most people would split this into header and source files (declaration/implementation, respectively). Is there any reason I can't just leave it in the header file if I'm going to use it across many source files? If so, are there any tools that will automatically convert it to declaration/implementation for me? Can someone show me what this would look like split into header/source file for an example (or just part of it, anyway)? I get confused around weird stuff like thistypedef boost::shared_ptr<tcp_connection> pointer; Do I include this in the header or the source? Same with tcp::socket& socket()

I've read many tutorials, but this has always been something that has confused me about C++.

A: 

with templates, it's very typical to implement them straight in the header file.

this is probably the simplest solution to linkage problems that may appears if you try to implement the template functions in a cpp file.

see this faq for more info.

Omry
However, his class is a class, not a class template.
James McNellis
seems to extend a template to me. the question was not if he can or cannot split it, but rather why his example (and so many others) do not.
Omry
A: 

You can split template class code into a implementation file, you include this file at the and of your header file. ACE (Adaptive Communication Framework) uses this procedure heavily. Therefore, I recommend you check it out.

baris_a
+1  A: 

Splitting this could look like this:

// in the header-file
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
  typedef boost::shared_ptr<tcp_connection> pointer;

  static pointer create(boost::asio::io_service& io_service);
  tcp::socket& socket();
  void start();
private:
  tcp_connection(boost::asio::io_service& io_service);
  void handle_write(const boost::system::error_code& /*error*/,
      size_t /*bytes_transferred*/);

  tcp::socket socket_;
  std::string message_;
};

// in the cpp-file

// #using the namespace in which the class was declared here

tcp_connection::pointer tcp_connection::create(boost::asio::io_service& io_service)
  {
    return pointer(new tcp_connection(io_service));
  }

  tcp::socket& tcp_connection::socket()
  {
    return socket_;
  }

  void tcp_connection::start()
  {
    message_ = make_daytime_string();

    boost::asio::async_write(socket_, boost::asio::buffer(message_),
        boost::bind(&tcp_connection::handle_write, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

  tcp_connection::tcp_connection(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  void tcp_connection::handle_write(const boost::system::error_code& /*error*/,
      size_t /*bytes_transferred*/)
  {
  }

Basically, all the method implementations have been moved to the cpp-file. typedef boost::shared_ptr<tcp_connection> pointer; defines an alias for a type and remains in the header.

To understand the rationale of splitting classes, look here and here. To understand the rationale behind not doing it, look here. A reason for not splitting that follows from the previous two is, that this way you do not have to link anything to use the class. You only have to include the header. Hope that gives you a starting point.

Space_C0wb0y