在阅读一本关于C ++模板的非常好的书时,我遇到了一些我不理解的模板替代方法的解释:
这些是C ++模板的不良替代品
- 您可以编写常见基本类型的通用代码,例如Object或void *。
醇>原因:如果您为公共基类编写通用代码 失去了类型检查的好处。此外,课程可能是 需要从特殊基类派生,这使得它更多 难以维护您的代码。
有人可以用代码示例来解释这个吗?
答案 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 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
与真实混乱进行比较。