Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;多态性-自动检测派生类型_C++_Oop_Polymorphism - Fatal编程技术网

C++ C++;多态性-自动检测派生类型

C++ C++;多态性-自动检测派生类型,c++,oop,polymorphism,C++,Oop,Polymorphism,我有一些我想优化的代码。看起来是这样的: function abc( string format ) { if (format == "a") { // this is a string, I shouldn't have used single quote, sorry for the confusion classx::a t; doit(t); } if (format == "b"){ classx::b t; doit(t); } i

我有一些我想优化的代码。看起来是这样的:

function abc( string format ) {
  if (format == "a") { // this is a string, I shouldn't have used single quote, sorry for the confusion
    classx::a t;
    doit(t);
  }
  if (format == "b"){
    classx::b t;
    doit(t);
  }
  if (format == "c"){
    classx::c t;
    doit(t) 
  }
  if (format == "d"){
    classx::d t; 
    doit(t);
  }
}
目前有许多不同类型的doit()函数

function doit( classx:a ) {
   different code for a
}

function doit( classx:b ) {
   different code for b
}
…等等

如您所见,大量代码被复制。但是我不知道如何减少单词。 请注意: doit(x)已被不同类型重载。 a、 b、c、d类是从一个名为“X”的类派生而来的

我可以创建指针类型classx::X:

classx::X *t;
if (format == "a") t = new classx::a
if (format == "b") t = new classx::b
if (format == "c") t = new classx::c
if (format == "d") t = new classx::d
doit(*t)
但是仍然需要为classx::X类型编写一个doit(),并使用一堆“if-then”并转换为正确的类型。。。因为C++不能自动检测和转换为正确的类型。 我想知道是否有更快/更聪明的方法来做到这一点。
提前感谢。

将格式/构造函数对放入字典中。关键是格式字符串,值是指向静态工厂方法的函数指针,该方法本质上只是构造函数上的一个薄包装。除了更易于维护外,它还可以根据您使用的字典/映射的类型进行哈希查找或二进制搜索。

如果在第一个
if
之后使用
else if
,速度会更快,这样在找到匹配项后它就不会继续测试。这是更紧凑和更简单的阅读以及

function abc(string format) {
    if (format == 'a')
        doit(classx::a());
    else if (format == 'b')
        doit(classx::b());
    else if (format == 'c')
        doit(classx::c())
    else if (format == 'd')
        doit(classx::d());
}

这里有一种使用宏的方法,它假设格式实际上是一个字符串。您在原始(Javascript?)代码中使用的单引号用于字符

我无法使用模板远程计算出任何紧凑的内容,是的,有时宏仍然有用

#define FORMATTER(ltr) \
    if (format == #ltr) { \
    classx::##ltr t; \
    doit(t); \
  }

#define ELSEFORMATTER(ltr) else FORMATTER(ltr)

void abc( std::string format ) {
    FORMATTER(a)
    ELSEFORMATTER(b)
    ELSEFORMATTER(c)
    ELSEFORMATTER(d)
}

使用boost预处理器

#define MACRO(r, data, elem)                     \
if (format == '(elem)')  doit(classx::(elem)()); \
else

BOOST_PP_SEQ_FOR_EACH(MACRO, _, (a)(b)...) {
... // else condition
}

我不知道如何将宏放入
中,但是:

一种可能的方法可以减少向函数映射添加新项的重复:

template<class T> void innerAbc() {
    T t;
    doit(t);
}

typedef std::map<std::string, void (*)()> FuncMap;

FuncMap initHandlers() {
    FuncMap m;
    m["a"] = &innerAbc<classx::a>;
    // ... extend here
    return m;
}   

void abc(const std::string& format) {
    static const FuncMap handlers = initHandlers();
    FuncMap::const_iterator it = handlers.find(format);
    if (it != handlers.end()) 
        it->second();
}
模板无效innerAbc(){
T;
doit(t);
}
typedef std::map FuncMap;
FuncMap initHandlers(){
FuncMap;
m[“a”]=&innerAbc;
//…延伸到这里
返回m;
}   
无效abc(常量标准::字符串和格式){
静态常量FuncMap handlers=initHandlers();
FuncMap::const_迭代器it=handlers.find(格式);
if(it!=handlers.end())
它->第二个();
}

一种简单的模板方法可以消除大量重复的代码。如果希望避免出现一系列“If”语句,可以使用映射或排序向量进行二进制搜索

template<typename T> void forward_doit()
{
    T t;
    doit(t);
}

void func(string const& s)
{
    if (s == "a") return forward_doit<Classx::a>();
    if (s == "b") return forward_doit<Classx::b>();
    if (s == "c") return forward_doit<Classx::c>();
    // ...
}
template void forward\u doit()
{
T;
doit(t);
}
无效函数(字符串常量(&s)
{
如果(s==“a”)返回前向_doit();
如果(s==“b”)返回前向_doit();
如果(s==“c”)返回前向_doit();
// ...
}


虽然这可以完成他要求的任务,但它会在不需要的地方引入复杂性。抛开你的战略否决票不谈,这是一个更好的想法,因为它可以很好地扩展,而且非常干净。在启动期间,每个类都可以向工厂注册自己,这可以是完全动态的。这是一个最佳实践。自注册无法扩展,因为它不能很好地与库配合使用。链接器不安排调用库中的所有全局(静态)构造函数,只调用与直接引用的代码位于同一编译单元中的那些构造函数。@Ben:这是一个很好的观点,但有多种方法可以解决这个问题。最糟糕的情况是,每个类RegisterMySelf函数都必须在使用工厂之前的某个时间点调用,这仍然比使用一个代码块硬编码所有子类要好。对不起,我不明白。你能给我一个示例代码吗?“指向静态工厂的函数指针”的返回是什么?感谢策略性的否决票,但您的解决方案实际上是朝着错误方向迈出的一步。如果他们完全不使用数据结构,那么正确的答案是switch/case。它不仅避免了在找到匹配项后进行不必要的测试,而且一些编译器还通过查找表甚至完美的散列进一步优化了它。在解释了你的答案不好的原因后,我认为没有理由对你投反对票。我将
if
语句列表更改为使用
else if
,以避免出现这种情况。一个好的优化编译器无论如何都会优化它,只是说。另外,switch语句只有在参数是
char
而不是
string
时才起作用。只是为了澄清一下。。。我故意把它放在字符串中,因为在我的实际代码中,格式更复杂,不能使用switch。不要忘记,如果你对你的领域有大量的了解,并且如果它在案例的频率上有很大的变化,那么对if-else-if的合理排序可能比switch更有效。不过,我同意在大多数情况下,在开关中使用char值更可取。我更仔细地阅读了您的问题,所以现在我想知道您的意思是重写而不是重载。你能确认一下吗?你有多少这样的条件?在我看来,如果你只有四个孩子,那么你的表现非常好。你可以使用Boost预处理器来自动实现样板,这是真的C++还是伪代码?这个问题看起来基本上类似于如果我正确地理解这个问题,你可以使用几个问题的答案中推荐的技巧。可能是使用工厂函数。@Steven:我认为它重载了,因为只有参数的类型不同@方舟:伪。。。这不是我的实际代码,我只是复制表格@aaa:我计划添加超过4:)@詹姆斯:谢谢。。我将研究这是一种缩短代码量的好方法,但它不能解决更深层次的问题。也就是说,这仍然是对正确类型的线性搜索,需要
func
了解基的所有子级。不可维护。@Steven:它是否可维护取决于问题中未说明的因素。我们不知道线性搜索是更好还是更差,因为我们不知道有多少项,也不知道一些项是否比其他项调用得更频繁。而func()需要了解所有的imp