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