考虑如下两个容器的定义:
template <typename T>
class Math_container {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
bool operator==(const Math_container& a) const
{
if (size() != a.size())
return false;
for (int i = 0; i < size(); ++i)
if ((*this)[i] != a[i])
return false;
return true;
}
};
template <typename T>
class Music_container {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
bool operator==(const Music_container& a) const
{
if (size() != a.size())
return false;
for (int i = 0; i < size(); ++i)
if ((*this)[i] != a[i])
return false;
return true;
}
};
两个类的operator==是一样的,没有必要存在两份完全一样的定义,所以应该抽取出来放在共同的基类中,然而基类operator==的实现依赖于派生类的某些成员函数,解决这种问题的典型做法是使用虚函数:在基类中定义虚函数,在派生类中改写。
template <typename T>
class Basic_ops
{
public:
virtual size_t size() const = 0;
virtual const T& operator[] (size_t i) const = 0;
bool operator==(const Basic_ops& a) const
{
if (size() != a.size())
return false;
for (int i = 0; i < size(); ++i)
if (operator[](i) != a[i])
return false;
return true;
}
};
template <typename T>
class Math_container : public Basic_ops<T> {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
};
template <typename T>
class Music_container : public Basic_ops<T> {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
};
但是虚函数有一个最大的问题:被调用的函数只有在执行期间才能确定下来。如果能在编译期间就确定下来,执行速度肯定会有所提高。为了做到这一点,基类必须知道派生类的类型信息,这一点可以通过将派生类的类型作为模板参数传递给基类来实现。
template <typename C>
class Basic_ops
{
public:
const C& derived() const
{
return static_cast<const C&>(*this);
}
bool operator==(const C& a) const
{
if (derived().size() != a.size())
return false;
for (int i = 0; i < derived().size(); ++i)
if (derived()[i] != a[i])
return false;
return true;
}
};
template <typename T>
class Math_container : public Basic_ops<Math_container<T> > {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
};
template <typename T>
class Music_container : public Basic_ops<Music_container<T> > {
public:
size_t size() const
{
// trivial implemention
return 0;
}
const T& operator[] (size_t i) const
{
// trivial implemention
static T data;
return data;
}
};
就是这样。