- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在使用虚拟类时遇到了一个奇怪的情况,我需要设计方面的帮助。
我有解决方案,但我正在寻找更好的解决方案。这是我编写的代码,它实现了我正在寻找的东西,但它依赖于指向指针的指针。
我觉得如果我可以直接操作共享指针的底层数据指针,我就可以少一层抽象。
我想用一个 InterfaceWrapper 来做到这一点,而不是两个。
#include <stdio.h>
#include <memory>
#include <vector>
class Interface
{
public:
virtual void WriteIt() = 0;
virtual ~Interface() { }
};
class Foo : public Interface
{
void WriteIt() { printf ("Foo\n"); }
};
class Bar : public Interface
{
void WriteIt() { printf ("Bar\n"); }
};
// This class wraps Interface so we can call WriteIt on desctruction
// I'd like to do this in the Interface class, but you can't call virtual methods during destruction.
class InterfaceWrapper : public std::unique_ptr<Interface>
{
public:
InterfaceWrapper(Interface * i) : std::unique_ptr<Interface>(i) { }
~InterfaceWrapper() { (*this)->WriteIt(); }
};
// This class provides counted destruction to InterfaceWrapper
class InterfaceWrapper2
{
public:
InterfaceWrapper2 () : _ptr(new InterfaceWrapper(new Foo)) { }
void MakeBar() { _ptr->reset(new Bar); }
private:
std::shared_ptr<InterfaceWrapper> _ptr;
};
int main (void)
{
std::vector<InterfaceWrapper2> thing_vector;
// The default implementation will, print "Foo" on destruction.
InterfaceWrapper2 thing;
// That destructor should only happen once for all copies of 'thing'
thing_vector.push_back(thing);
// MakeBar changes the virtual implementation so it prints "Bar" instead of "Foo"
thing.MakeBar();
// When destructors happen, the program should just print "Bar" once.
return 0;
}
任何东西都是受欢迎的,但我对使用 boost 在 C++03 上工作的解决方案特别感兴趣(我的示例是 C++11,但我的“真实”代码是使用 boost::shared_ptr 的 C++03)。
我基本上是在寻找一种更好的方法来在我的示例代码中实现 InterfaceWrapper2。 main()
是对我想要完成的事情的最好解释。请记住,行为停留在那些虚拟类中。
最佳答案
这就是你想要的吗?
更新 3
如果你想保留接口(interface)机制,下面是一个非常简洁的方法来编写包装器,只需组合标准库功能:
class InterfaceWrapper {
using UI = std::unique_ptr<Interface>;
std::shared_ptr<UI> _sui {new UI{new Foo}, [](UI*p){ (*p)->WriteIt(); delete p; }};
public:
void MakeBar() { _sui->reset(new Bar); }
};
更新 2
在意识到 std::function<>
已经是一个动态的、单函数的、可变的接口(interface),可以绑定(bind)到任何有状态的仿函数,我想到了以下简化版本:
#include <memory>
#include <iostream>
#include <vector>
struct dynamic_release {
template <typename F> dynamic_release(F&& f) : _f(std::forward<F>(f)) { }
template <typename F> dynamic_release& operator=(F&& f)
{ _f = std::forward<F>(f); return *this; }
~dynamic_release() { _f(); }
private:
std::function<void()> _f;
};
void do_foo() { std::cout << "Foo\n"; }
void do_bar() { std::cout << "Bar\n"; }
int main(void) {
using InterfaceWrapper = std::shared_ptr<dynamic_release>;
using Thing = InterfaceWrapper::element_type;
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>(do_foo);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
} // prints "Foo" once
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>(do_foo);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
*thing = do_bar; // Prints nothing
thing_vector.push_back(thing);
} // prints "Bar" once
}
如果您也想通过无状态仿函数实现更高效率,要启用优化,请添加 basic_dynamic_release
允许使用不同仿函数类型的模板(例如 void(*)()
):
#include <memory>
#include <iostream>
namespace detail {
template <typename InterfaceCallable>
struct basic_dynamic_release {
basic_dynamic_release() = default;
template <typename F> basic_dynamic_release(F&& f) : _f(std::forward<F>(f)) { }
template <typename F> basic_dynamic_release& operator=(F&& f)
{ _f = std::forward<F>(f); return *this; }
~basic_dynamic_release() { _f(); }
private:
InterfaceCallable _f;
};
}
using dynamic_release = detail::basic_dynamic_release<std::function<void()>>;
#include <vector>
void do_foo() { std::cout << "Foo\n"; }
void do_bar() { std::cout << "Bar\n"; }
int main(void) {
using InterfaceWrapper = std::shared_ptr<detail::basic_dynamic_release<void(*)(void)>>;
using Thing = InterfaceWrapper::element_type;
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>(do_foo);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
} // prints "Foo" once
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>(do_foo);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
*thing = do_bar; // Prints nothing
thing_vector.push_back(thing);
} // prints "Bar" once
}
为了让默认构造的实例具有定义良好的接口(interface)实现,添加一个工厂(这是为了使其非常通用):
#include <memory>
#include <iostream>
namespace detail {
template <typename T> struct default_construction final {
T operator()() const { return {}; }
};
template <typename InterfaceCallable, typename Factory = default_construction<InterfaceCallable> >
struct basic_dynamic_release {
basic_dynamic_release() = default;
template <typename F> basic_dynamic_release(F&& f) : _f(std::forward<F>(f)) { }
template <typename F> basic_dynamic_release& operator=(F&& f)
{ _f = std::forward<F>(f); return *this; }
~basic_dynamic_release() { _f(); }
private:
InterfaceCallable _f = Factory()();
};
using dynamic_interface = std::function<void()>;
template <typename Factory = default_construction<dynamic_interface> >
using dynamic_release = basic_dynamic_release<dynamic_interface, Factory>;
}
#include <vector>
void do_foo() { std::cout << "Foo\n"; }
void do_bar() { std::cout << "Bar\n"; }
struct foo_default { detail::dynamic_interface operator()() const { return do_foo; } };
int main(void) {
using InterfaceWrapper = std::shared_ptr<detail::dynamic_release<foo_default> >;
using Thing = InterfaceWrapper::element_type;
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>();
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
} // prints "Foo" once
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>();
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
*thing = &do_bar; // Prints nothing
thing_vector.push_back(thing);
} // prints "Bar" once
}
旧答案倾向于使用 boost::variant
的静态多态性,以管理更复杂为代价,但具有更大的灵 active :
I opted to replace the dynamic polymorphism with static polymorphism, which removes the extra allocation, which also takes with it the lifetime management (what used to be the
unique_ptr
).I think this makes resulting solution a bit simplified, and at the same time more generic (naturally provides some extension points).
#include <boost/variant.hpp>
#include <memory>
#include <iostream>
namespace nature { // detail namespace
template <typename> struct Nature;
template<> struct Nature<struct FooTag> { void do_it() { std::cout << "Foo" << "\n"; } };
template<> struct Nature<struct BarTag> { void do_it() { std::cout << "Bar" << "\n"; } };
using FooNature = Nature<FooTag>;
using BarNature = Nature<BarTag>;
using AnyNature = boost::variant<FooNature, BarNature>;
struct Holder {
AnyNature held;
~Holder() { DoIt()(held); }
private:
struct DoIt : boost::static_visitor<> {
void operator()(AnyNature& any) const { return boost::apply_visitor(*this, any); }
template <typename N> void operator()(N& nature) const { return nature.do_it(); }
};
};
}
#include <vector>
int main(void) {
using InterfaceWrapper = std::shared_ptr<nature::Holder>;
using Thing = InterfaceWrapper::element_type;
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>(); // FooNature is default
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
} // prints "Foo" once
{
std::vector<InterfaceWrapper> thing_vector;
auto thing = std::make_shared<Thing>();
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing_vector.push_back(thing);
thing->held = nature::BarNature {}; // prints nothing
thing_vector.push_back(thing);
} // prints "Bar" once
}Prints
Foo
Bar
关于C++ 共享指针。如何更改所有拷贝的基础对象指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27260057/
我有一个基类和两个派生类,我需要将一个指向派生类对象的指针复制到另一个类中,就像示例一样。 class Base { public: Base(const Base& other); } cl
考虑 Container 类,它主要存储 Box 对象的 unique_ptr vector ,并可以对它们执行一些计算。 class Container { private: std::
引用是指保存的值为对象的地址。在 Python 语言中,一个变量保存的值除了基本类型保存的是值外,其它都是引用,因此对于它们的使用就需要小心一些。下面举个例子: 问题描述:已知一个列表,求生成一个
我正在尝试实现 Bron-Kerbosch 算法,这是一种用于查找派系的递归算法。我设法达到了一个点,它返回了正确数量的派系,但是当我打印它们时,它们不正确 - 添加了额外的节点。我在这里遗漏了什么明
在评估中,我选择了选项LINE I 上的运行时错误。没有未定义行为这样的选项,尽管我认为这是正确的选择。 我不确定,但我认为评估有误。我编译并运行了该程序,它确实打印了 3, 9, 0, 2, 1,
在函数签名中通过 const 值传递参数是否有任何好处(或相反,成本)? 所以: void foo( size_t nValue ) { // ... 对比 void foo( const s
我为 answer to another question 写了一个 OutputIterator .在这里: #include using namespace std; template clas
我有一个由第三方生成的 dll,它具有某种内部数据结构,将其大小限制为 X 个元素。 所以基本上,它有一个以 X 为限制的队列。 据我所知,DLL 是每个进程的,但是是否可以多次加载 DLL?也许每个
假设我有以下两个数据结构: std::vector all_items; std::set bad_items; all_items vector 包含所有已知项和 bad_items vector
如何在不渲染 CGImage 的情况下从另一个 CIImage 复制一个 CIImage 最佳答案 CIImage *copiedImage = [originalImage copy]; 正如您在
我有一个名为 UINode 的 GUI,我想创建一个拷贝并只更改一些内容。该项目由 3 个基本线程组成。 PingThread、RosThread 和 GuiThread。我试图复制粘贴项目文件夹并将
Qt 新手。如果这个问题太幼稚,请多多包涵。在 Windows 操作系统环境中,我有 Qt 对话框框架应用程序,它具有“重复”- 按钮。在同一目录中,有 Qt 应用程序 - (一个带有关闭按钮的对话框
我正在尝试创建一个函数来复制我的卡片结构。我只需复制 cvalue 即可轻松开始。然而,我的 cvalue 没有复制,当应该读取 1000 时它仍然读取 5。 #include #include
string str1("someString"); string str2 = string(str1);//how many copies are made here //copy2 =
我希望了解 boost::bind 执行何种函数对象的内部拷贝。由于这些对象的构造函数似乎没有被调用,我推测这是一种“非常浅的复制”,所以我引入了动态内存分配来产生一些错误。但是,下面代码的运行时输出
我正在查看 http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c22-make-default-operations-consis
下面的类方法Augmented3dPoint::getWorldPoint()返回对其成员的引用 cv::Point3f world_point; class Augmented3dPoint { p
我需要通过 MyClass2 将用户定义的 lambda 传递给 MyClass1。我想确保只有一步,没有拷贝。下面的代码实现了吗?有没有更好的方法来做到这一点(比如使用编译器完成的隐式移动)? 注意
在我的数据库访问代码中,我想写一个方法: variant_t GetQueryRows (...) 我想这样调用它: const variant_t result = GetQueryRows (..
我有一个包含引用的类,例如: class A { A(B &b) : b(b) {} // constructor B &b; } 有时b必须是只读的,有时是可写的。当我创建一个 const A
我是一名优秀的程序员,十分优秀!