[英]Avoiding dynamic_cast in implementation of virtual functions in derived class
这是一些示例代码,解释了我想要实现的目标。
基本上,我有一个算法,它依赖于类中可用的一些基本操作。 我已经在纯抽象基类中定义了这些操作。 我想将该算法应用于各种对象,这些对象通过派生特定对象的类来提供这些操作。
但是,就这些操作而言,不同的派生对象彼此不兼容。 我的问题是我是否可以避免使用RTTI来确保例如bool derived2 :: identical(const base * other2),断言(或其他退出机制)其中other2不是derived2类型。
一种替代方法是在特定的派生对象上模拟函数算法,但这意味着它的实现必须存在于我不想做的头文件中1)为了测试目的而更改算法代码会导致重新编译大部分代码2)算法的实现将在头文件中公开,而不是生活在最终用户隐藏的源文件中。
#include <list>
class base
{
public:
virtual float difference(const base*) const = 0;
virtual bool identical(const base*) const = 0;
};
class derived1 : public base
{
public:
float difference(const base* other1) const
{
// other1 has to be of type derived1
if(typeid(other1) == typeid(this))
{
// process ...
}
else
{
assert(0);
}
return 1;
}
bool identical(const base* other1) const
{
// other1 has to be of type derived1
if(typeid(other1) == typeid(this))
{
// compare...
}
else
{
assert(0);
}
return true;
}
};
class derived2 : public base
{
public:
float difference(const base* other2) const
{
// process ...
// other2 has to be of type derived2
return 2;
}
bool identical(const base* other2) const
{
// do comparison
// derived1 and derived2 cannot be compared
return true;
}
};
// Declaration
int algorithm(std::list<base*>& members);
#include "header_file_containing_base"
int algorithm(std::list<base*>& members)
{
// This function only relies on the interface defined in base
// process members;
return 1;
}
int main()
{
// Create lists of derived1 and derived2
// Run algorithm on these lists
}
您可以使用双重调度( http://en.wikipedia.org/wiki/Double_dispatch )
嗯,有一个简单的事情:将真实类型存储为成员。
enum
,将所有类型分组。 如果你有很多它会变得很麻烦。 我将说明工厂ID:
class IdFactory
{
public:
template <class T>
static size_t GetId(T const&) // argument deduction
{
static size_t const Id = GetIdImpl();
return Id;
}
private:
static size_t GetIdImpl()
{
static size_t Id = 0;
return ++Id;
}
}; // class IdFactory
你可以像这样使用它:
class Base
{
public:
explicit Base(size_t id): mId(id) {}
size_t const mId; // meaningless to change it afterward...
private:
};
class Derived: public Base
{
public:
explicit Derived(): Base(IdFactory::GetId(*this)) {}
};
然后,您可以使用mId
成员进行测试。 请注意,因为它是const
所以它可以暴露...否则你可以创建一个内联const
getter ...
float Derived::difference(const Base& rhs)
{
assert( IdFactory::GetId(*this) == rhs.mId );
// ...
}
这里的成本可以忽略不计:
GetId
是内联的,因此没有函数调用 GetId
是懒惰地初始化的,除了初始化它相当于检查static
成员是否已经初始化:它通常被实现为if
语句,条件总是评估为true(除了第一次)。 ==
通常很快;) 唯一的缺点是,您确实需要确保正确初始化ID。
还有一个无存储解决方案,涉及虚函数调用:
class Other: public Base
{
public:
virtual size_t id() const { return IdFactory::GetId(*this); }
};
实践更容易,因为不存储const
成员意味着您不必自己编写作业。
您可以使用模板化功能。 使用模板,可以在以后添加更多类,而无需更改原始类,只需在另一个头文件中添加另一个模板函数即可。 如果唯一的问题是编译速度 - 您可以在除标题之外的源文件中实现模板函数并使用显式模板实例化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.