c++ - 如何在源/标题中拆分下面的示例代码?
问题描述
有没有一种很好的方法将以下示例 C++ 代码拆分为源代码和标头,这样服务器的所有用户都不需要间接包含实际上只需要服务器内部的标头? Daytime.3 的源列表
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
using namespace std; // For time_t, time and ctime;
time_t now = time(0);
return ctime(&now);
}
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_;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
}
start_accept();
}
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
由于某种原因,我能找到的大多数示例都假设所有代码都在一个文件中。
这个问题可能看起来很愚蠢,但每次我尝试重构它时,一些模板都会崩溃。我真的可以使用这个例子。
解决方案
对此的一般答案是使用 Pimpl Idiom。您可以使标题尽可能简单
#pragma once
#include <memory>
class tcp_server {
public:
tcp_server();
~tcp_server();
void run();
private:
struct impl;
std::unique_ptr<impl> _pimpl;
};
那么main.cpp
可以是:
#include "server.h"
#include <iostream>
int main()
{
try {
tcp_server server;
server.run();
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
}
}
当然,这留下了您如何实施的问题test.cpp
:
tcp_server::tcp_server() : _pimpl(std::make_unique<impl>()) {}
void tcp_server::run() { _pimpl->run(); }
并且所有的逻辑都移到了实现类型中,所有的本地函数都可以有文件链接。
现场演示
文件
test.cpp
#include "server.h" #include <iostream> int main() { try { tcp_server server; server.run(); } catch (std::exception const& e) { std::cerr << e.what() << std::endl; } }
文件
server.h
#pragma once #include <memory> class tcp_server { public: tcp_server(); ~tcp_server(); void run(); private: struct impl; std::unique_ptr<impl> _pimpl; };
文件
server.cpp
#include "server.h" #include <boost/asio.hpp> #include <boost/bind/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/shared_ptr.hpp> #include <ctime> #include <string> using boost::asio::ip::tcp; namespace /*anonymous, file linkage*/ { static std::string make_daytime_string() { using namespace std; // For time_t, time and ctime; time_t now = time(0); return ctime(&now); } class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer; static pointer create(boost::asio::any_io_executor executor) { return pointer(new tcp_connection(executor)); } 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::any_io_executor executor) : socket_(executor) { } void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } tcp::socket socket_; std::string message_; }; } // namespace struct tcp_server::impl { void run() { io_service_.run(); } void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_executor()); acceptor_.async_accept(new_connection->socket(), boost::bind(&impl::handle_accept, this, new_connection, boost::asio::placeholders::error)); } void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(); } start_accept(); } boost::asio::io_service io_service_; tcp::acceptor acceptor_{io_service_, tcp::endpoint(tcp::v4(), 13)}; }; tcp_server::tcp_server() : _pimpl(std::make_unique<impl>()) {} tcp_server::~tcp_server() = default; void tcp_server::run() { _pimpl->run(); }
推荐阅读
- java - 如何在while循环中使用switch case将base 10转换为任何base?
- nativescript - 无法通过点击按钮在 android 上播放声音
- mysql - 使用 mysql 从所有数据库中获取所有表
- c++ - 为什么这只有一半回溯?
- python - x86-64 程序集 - 在堆栈上创建一个字符串或为 CreateFile 创建一个寄存器
- python - Python os.system grep 与 bash grep 的结果不同
- kubernetes - 来自 kubernetes 秘密的掌舵值?
- google-app-engine - “内存”和“带宽”是否相同?在 Google App Engine 中是什么意思?
- angular - 编辑新添加的行并更新对该行的更改,而不是使用 angular8 中的 formArray 反应形式创建新项目
- javascript - 在 Wasm 中运行 go 时如何更正此问题