如何在C ++中使用动态方法

时间:2009-09-23 01:28:15

标签: c++

我发现自己在C ++中编写了一些重复的代码。我正在使用一些自动生成的,如果我想处理Foo,Bar和& Baz他们都有相当类似的方法。例如,get_foo,get_bar,get_baz等

对于每一件“事物”,我或多或少都要做同样的事情。检查它是否存在,是否存在,获取日志,查找日志中的最新条目,检查条目以查找问题等。

这导致了相当多的重复代码,如下所示:

if (obj->has_foo) {
  if(obj->get_foo().has_log()) {
    Log *l = obj->get_foo().get_foo_log();
    if (!l) {
      ERROR("Foo does not have a log")
    }    
    ... 30-40 more lines of stuff ...
  }
}

if (obj->has_bar) {
  if(obj->get_bar().has_log()) {
    Log *l = obj->get_bar().get_bar_log();
    if (!l) {
      ERROR("Bar does not have a log")
    }    
    ... 30-40 more lines of stuff ...
  }
}

if (obj->has_baz) {
  if(obj->get_baz().has_log()) {
    Log *l = obj->get_baz().get_baz_log();
    if (!l) {
      ERROR("Baz does not have a log")
    }    
    ... 30-40 more lines of stuff ...
  }
}

有没有办法构建一个集合,这样集合中的每个项目都有Foo,Bar,Baz的独特方面,我可以在一个代码块中使用它们。

原谅Perl-eese,但有点像:

foreach my $thingie ("foo", "bar", "baz") {
    if (obj->has_$thingie) {
      if(obj->get_$thingie().has_log()) {
        Log *l = obj->get_$thingie().get_$thingie_log();
        if (!l) {
          ERROR(sprintf("%s does not have a log", $thingie))
        }    
        ... 30-40 more lines of stuff ...
      }
    } 
}

或者,如果这不是正确的方向,我如何避免复制/粘贴/调整相同的基本块3次?

4 个答案:

答案 0 :(得分:12)

当然(代码未经测试,我可能已经错过了成员指针和类型演绎的一些问题,或者我可能只是留下了错误):

template <typename T, typename M, typename F, typename G>
void doChecks(T *obj, M has_member, F get_fn, G getlog_fn) {
    if (obj->*has_member) {
        if (obj->*get_fn().has_log()) {
            Log *l = obj->*get_fn().*getlog_fn();
            if (!l) {
                ERROR("%s does not have a log", typeid(T).name());
            }
        }
     }
}

MyObj obj;
doChecks(obj, &MyObj::has_foo, &MyObj::get_foo, &Foo::get_foo_log);
doChecks(obj, &MyObj::has_bar, &MyObj::get_bar, &Bar::get_bar_log);
doChecks(obj, &MyObj::has_baz, &MyObj::get_baz, &Baz::get_baz_log);

显然你可以使用仿函数类型的模板参数,但这是最接近perl方法而不实际在对象中构建字典并滚动自己的调度。你可以根据需要宏观调用doChecks,并使用一些令牌粘贴来缩短它们:

#define DOCHECKS(obj, class, thing) doChecks(obj, &MyObj::has_##thing, &MyObj::get_##thing, & class :: get_##thing##log) 

DOCHECKS(obj, Foo, foo);
DOCHECKS(obj, Bar, bar);
DOCHECKS(obj, Baz, baz);

使用额外的预处理器魔法,你可能会使它成为一个循环,不确定。查看Boost预处理器库或Chaos预处理器。

答案 1 :(得分:2)

我认为你需要滚动你自己的间接,可能使用std :: map来存储“foo”,“bar”和“baz”的键,关联的值是带有“get_log”方法的对象(假设你在get_foo()返回的对象上不需要get_foo_log()。在您的Perl-eese中,它可能会变为以下内容:

foreach my $thingie ("foo", "bar", "baz") {
    if (obj->has($thingie)) {
        if (obj->get($thingie).has_log()) {
            Log *l = obj->get($thingie).get_log();
            if (!l) {
                ERROR(...)
            }
            ... more lines ...
        }
    }
}

答案 2 :(得分:0)

C ++不支持动态方法 所有方法都在编译时严格定义。

但是30/40行代码可以通过函数调用来完成:

 if (!l)
 {
     ERROR("Bar does not have a log");
     return;
 }    
 //... 30-40 more lines of stuff ...
 LogStuff(*l);

你显然使用C ++的方式对你来说很自然: 所以我有几个问题:

  • 你来自哪种语言?
  • 你想做什么?

答案 3 :(得分:0)

请你再解释一下你的问题了吗? obj可以同时包含三个:'' 即所有三个条件都可以          1)if(obj-&gt; has_foo)          2)if(obj-&gt; has_bar)          3)if(obj-&gt; has_baz)

我建议你编写一个具有通用功能的基类。从该基类驱动所有三个foo,bar adn baz,现在使用基类指针执行调用。小号 所以你不需要重复所有三个代码。