草庐IT

c++ - 允许用户包含类而不包含用于私有(private)的 header

coder 2024-02-09 原文

抱歉标题又长又乱。

我有一个这样的类头文件

#pragma once
#include <thread>
#include <boost/asio.hpp>
#include <another3rdpartylib/doodads.h>

class A {
public:
  A();
  Method1();
  Method2();
private:
  std::thread thread;
  boost::asio::socket socket;
  another3dpartylib::doodad gizmo;
}

现在类的用户不会也不应该关心私有(private)部分。 我怎样才能允许用户在不拖动的情况下包含类 <thread> , <boost/asio.hpp><another3rdpartylib/doodads.h>

从技术上讲,用户唯一应该关心的是 sizeof(A) .我错了吗?

最佳答案

C++中分离类的接口(interface)和实现的常用方法是使用Pointer To Implementation (PIMPL) Idiom .

PIMPL 习语通过存储对负责执行操作的类的引用/指针来封装类的实现,只为用户提供一个类,即接口(interface),它仅充当实现类的包装器.

例如:考虑一个为浮点运算实现极快堆栈的库。容器的接口(interface)非常简单:

class fast_stack
{
public:
    void push( float );
    float pop();
};

但是由于这个库实现了一个极快的堆栈,它的实现是基于极其复杂的库、内联汇编、brainfuck 互操作性等。

该库的用户只需要一个堆栈,而不是一堆可怕的代码、库和依赖项。 我们如何才能隐藏所有的尖叫声,只为他提供一个简单干净的界面?这就是 PIMPL 发挥作用的地方:

//stack_inferno.hpp

#include <thread>
#include <Boost/ASIO>
... More monters here

class fast_stack_infernal_implementation
{
   std::thread* _mptr_thread_lcl;
   float******* _suicide_cache_memory_pool;
   ... etc etc

   void push( float elem )
   {
        //Please don't see this code, it could hurt your eyes
   }

   float pop()
   {
        // Same as above
   }
};



//fast_stack.hpp (Revisited)

class fast_stack_infernal_implementation; //Note the forward declaration. 

class fast_stack
{
public:
    void push( float );
    float pop();

private:
    std::unique_ptr<fast_stack_infernal_implementation> implm;
};



//fast_stack.cpp

#include "stack_inferno.hpp" //Tah daah!


fast_stack::fast_stack() : impl( new fast_stack_infernal_implementation() )
{
}

void fast_stack::push( float elem )
{
     implm->push( elem );
}

float fast_stack::push()
{
     return implm->pop();
}

如您所见,PIMPL 习语有很多优点:

  • 向用户隐藏实现的复杂性,仅提供接口(interface)。
  • 用户头文件(接口(interface)头文件)不包含实现头文件,因此对实现的更改不会导致孔库和用户代码的重新编译。这一点对于库来说非常重要,因为对库的更改并不总是会破坏用户代码。

关于c++ - 允许用户包含类而不包含用于私有(private)的 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20804621/

有关c++ - 允许用户包含类而不包含用于私有(private)的 header的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  4. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  7. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  8. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  9. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  10. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

随机推荐