我有几个类需要以下 clone待定义函数:
struct Base
{
virtual Base * clone() const = 0;
};
struct A : public Base
{
Base * clone() const {
return new A(*this);
}
};
struct B : public Base
{
Base * clone() const {
return new B(*this);
}
};
struct X : public Base2
{
Base2 * clone() const {
return new X(*this);
}
};
我正在尝试使用 Cloneable mixin 来避免这种冗余代码:
template <typename BASE, typename TYPE>
class CloneableMixin
{
public:
BASE*clone() const {
return new TYPE( dynamic_cast<const TYPE &>(*this) );
}
};
struct A : public Base, public CloneableMixin<Base, A>
{
};
然而,这是行不通的,因为在new TYPE(*this)来自 CloneableMixin , *this类型为 CloneableMixin<BASE, TYPE> .
更新: CloneableMixin可以dynamic_cast到正确的类型。但现在我有另一个问题:CloneableMixin::clone没有成功覆盖 Base::clone ,因此编译器报告 A 是抽象类型。
可以巧妙地使用virtual吗?允许继承 CloneableMixin::clone覆盖 Base::clone ?我应该为此使用一些宏吗?
您知道解决所有这些冗余代码的方法吗?
最佳答案
Can some clever use of virtual inheritance allow CloneableMixin::clone to override Base::clone?
你的 CloneableMixin<Base,Derived>不能覆盖 Base 的任何方法- 任何一个
多态或隐藏 - 因为 CloneableMixin<Base,Derived>是
不是来自 Base .
另一方面,如果CloneableMixin<Base,Derived> 是源自Base
你将不再需要它是一个 mixin,因为 -
class Derived : public CloneableMixin<Base,Derived> {....};
会继承Base .
因此,对于您的示例的需要,此处说明的解决方案就足够了:
#include <iostream>
// cloner v1.0
template <class Base, class Derived>
struct cloner : Base
{
Base *clone() const override {
return new Derived( dynamic_cast<const Derived &>(*this) );
}
~cloner() override {};
};
struct Base
{
virtual Base * clone() const = 0;
Base() {
std::cout << "Base()" << std::endl;
}
virtual ~Base() {
std::cout << "~Base()" << std::endl;
}
};
struct A : cloner<Base,A>
{
A() {
std::cout << "A()" << std::endl;
}
~A() override {
std::cout << "~A()" << std::endl;
}
};
int main()
{
A a;
Base * pb = a.clone();
delete pb;
}
(如果您正在编译为 C++03 标准而不是 C++11,那么您可能
只需删除出现的 override关键字。)
这个解决方案将分解为一些更真实的类层次结构, 例如在这张 Template Method Pattern 的插图中:
#include <iostream>
#include <memory>
using namespace std;
// cloner v1.0
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
};
/* Abstract base class `abstract` keeps the state for all derivatives
and has some pure virtual methods. It has some non-default
constructors.
*/
struct abstract
{
virtual ~abstract() {
cout << "~abstract()" << endl;
}
int get_state() const {
return _state;
}
void run() {
cout << "abstract::run()" << endl;
a_root_method();
another_root_method();
}
virtual void a_root_method() = 0;
virtual void another_root_method() = 0;
virtual abstract * clone() const = 0;
protected:
abstract()
: _state(0) {
cout << "abstract(): state = " << get_state() << endl;
}
explicit abstract(int state) : _state(state) {
cout << "abstract(" << state << ") : state = "
<< get_state() << endl;
}
int _state;
};
/* Concrete class `concrete` inherits `abstract`
and implements the pure virtual methods.
It echoes the constructors of `abstract`. Since `concrete`
is concrete, it requires cloneability.
*/
struct concrete : cloner<abstract,concrete>
{
concrete() {
cout << "concrete(): state = " << get_state() << endl;
}
explicit concrete(int state) : abstract(state) { //<- Barf!
cout << "concrete(" << state << ") : state = "
<< get_state() << endl;
}
~concrete() override {
cout << "~concrete()" << endl;
}
void a_root_method() override {
++_state;
cout << "concrete::a_root_method() : state = "
<< get_state() << endl;
}
void another_root_method() override {
--_state;
cout << "concrete::another_root_method() : state = "
<< get_state() << endl;
}
};
int main(int argc, char **argv)
{
concrete c1;
unique_ptr<abstract> pr(new concrete(c1));
pr->a_root_method();
pr->another_root_method();
unique_ptr<abstract> pr1(pr->clone());
pr1->a_root_method();
return 0;
}
当我们尝试构建它时,编译器会在
初始化abstract(state)在 concrete 的构造函数中(在 Barf!
评论),说:
error: type 'abstract' is not a direct or virtual base of 'concrete'
或类似的词。事实上,concrete 的直接基础不是 abstract
但是cloner<abstract,concrete> .但是,我们不能将构造函数重写为:
/*Plan B*/ explicit concrete(int state) : cloner<abstract,concrete>(state){....}
因为没有这样的构造函数
cloner<abstract,concrete>::cloner<abstract,concrete>(int)
但是编译器的诊断建议修复。 这是是虚拟的
继承可以提供帮助。我们需要 abstract成为concrete的虚拟基地, 哪个
有效地意味着“concrete 的荣誉直接基地”,我们可以实现这一点
只需制作 B cloner<B,D> 的虚拟 基地:
// cloner v1.1
template<class B, class D>
struct cloner : virtual B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
};
这样,我们就有了一个干净的构建和输出:
abstract(): state = 0
concrete(): state = 0
concrete::a_root_method() : state = 1
concrete::another_root_method() : state = 0
concrete::a_root_method() : state = 1
~concrete()
~abstract()
~concrete()
~abstract()
~concrete()
~abstract()
原则上有充分的理由警惕虚拟继承 并保留它的使用至少在它具有建筑学的情况下 基本原理 - 不是为了解决方法,因为我们刚才已经使用了它。
如果我们更愿意在没有虚拟继承的情况下解决这个问题,那么我们
必须以某种方式确保有 cloner<B,D> 的构造函数那
回显 B 的任何构造函数, 对于任意 B .然后任意对应
D 的构造函数将能够初始化其直接基cloner<B,D>
无论争论是什么。
这是 C++03 的白日梦,但具有可变参数模板的魔力 C++11 中的参数很简单:
// cloner v1.2
template<class B, class D>
struct cloner : B
{
B *clone() const override {
return new D(dynamic_cast<D const&>(*this));
}
~cloner() override {}
// "All purpose constructor"
template<typename... Args>
explicit cloner(Args... args)
: B(args...){}
};
有了这个,我们可以重写 concrete构造函数为 /*Plan B*/ , 和
我们再次拥有正确的构建和可执行文件。
关于C++ 可克隆混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10443637/
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
我最近开始从事一个项目,该项目使用git进行存储并使用ruby作为前端。我的脚本的第一个版本使用了ruby-git,虽然非常简单,但还不错。当我需要对我的提交和日志做更具体的工作时,建议我转向砂砾。然而,我在早期遇到了障碍——grit似乎无法克隆远程存储库。我发现使用Repository类的所有示例都创建了一个本地存储库并搜索了我发现Grit的clone方法未定义的源代码。给了什么?这是我的第一个StackOverflow问题,在此先感谢您的帮助。 最佳答案 由于Git结构良好,Grit使用缺少的方法(Grit::Git#m
我有一个模块:moduleMyModuledefdo_something#...endend由类使用如下:classMyCommandextendMyModuledefself.execute#...do_somethingendend如何验证MyCommand.execute调用了do_something?我已经尝试使用mocha进行部分模拟,但是当未调用do_something时它不会失败:it"callsdo_something"doMyCommand.stubs(:do_something)MyCommand.executeend 最佳答案
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=
所以我只是对此感到好奇:DataMapper为其模型使用混合classPostincludeDataMapper::Resource虽然active-record使用继承classPost有谁知道为什么DataMapper选择这样做(或者为什么AR选择不这样做)? 最佳答案 它允许您从另一个不是DM类的类继承。它还允许动态地将DM功能添加到类中。这是我正在处理的模块中的类方法:defdatamapper_classklass=self.dupklass.send(:include,DataMapper::Resource)klass
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t