为什么编写通用基类型的通用代码是C ++中模板的不良替代?

时间:2014-09-06 02:06:19

标签: c++ templates polymorphism

在阅读一本关于C ++模板的非常好的书时,我遇到了一些我不理解的模板替代方法的解释:

  

这些是C ++模板的不良替代品

     
      
  1. 您可以编写常见基本类型的通用代码,例如Object或void *。
  2.         

    原因:如果您为公共基类编写通用代码   失去了类型检查的好处。此外,课程可能是   需要从特殊基类派生,这使得它更多   难以维护您的代码。

有人可以用代码示例来解释这个吗?

2 个答案:

答案 0 :(得分:6)

这不是普通基类型的概念。它是使用“对象类”,所有东西都必须从编写带有void*的代码,或者更糟糕的是,编写指针所指向的代码,对指向其他类型的指针进行类型转换。希望最好的。这最好以容器为例。

实现容器方法的正确方法是使用模板。例如:

template<typename T> void List<T>::append(const T& obj);

对象类

对于Object基类,这意味着您放入容器中的任何内容必须派生自Object,因为所有容器方法都使用Object*表示所述容器中的数据。所以你得到这样的方法:

void List::append(Object* obj);

这里有两件坏事:首先,无论你走到哪里,Object课都必须随身携带。其次,它是一个非常通用的名称,可能会与其他库中的Object类冲突。

此外,您的容器永远不能包含不直接派生Object的类型,包括int等基本类型和std::string等标准类型。您必须在Object子类中“包装”这些类型,然后您必须花时间使用代码从这些包装器对象中提取值等。后面的一个痛苦就是你不能需要。

void *的

所以你可能认为你可以使用通用指针void*代替:

void List::append(void* obj);

但是当你这样做时,容器可能需要做很多事情,但它不能,因为它不知道void*指向的是什么:

  • 无法复制数据对象。
  • 无法比较数据对象。
  • 无法删除数据对象。

等等。 (您可以使用虚拟方法在Object*案例中避免这些问题,例如声明如下内容:

virtual ~Object() {}
virtual Object* clone() const;
virtual int cmp(const Object* rhs) const;

这些方法必须Object基类中的所有子类覆盖。但是现在你的Object类不是很轻量级。)

在这两种情况下,对于容器的数据类型使用模板化类型会更好。如果您担心代码膨胀并且容器中的代码不关心数据类型(因为它不会打扰数据,例如计算包含的元素时),您可以将该代码放在基类中并让你的模板化容器类派生自它。但大部分时间没有人真正关心这种“臃肿”,因为它比你的可用内存小得多。

丢弃类型检查

  

如果编写公共基类的通用代码,则会失去类型检查的好处。

由于您的类型转换为Object*void*,因此大多数情况下类型检查都会在窗口中显示。 (注意:这有点过时,因为在某些情况下,您可以使用运行时类型标识(RTTI)和dynamic_cast操作来执行类型检查,以确保从容器中取出的对象是你期望的类型。但所有上述限制仍然适用,因为容器仍然不知道它包含什么。)

答案 1 :(得分:0)

旧的qsort function使用void*指针来指示数据的开头和比较函数的参数。您可以轻松尝试使用比较函数对double数组进行排序,该比较函数将int与真实混乱进行比较。