Mad*_*ire 1 c++ polymorphism templates
在阅读关于C++模板的非常好的书时,我遇到了一些关于模板替代方案的解释,我不明白:
这些是C++模板的不良替代品
- 您可以编写公共基类型的通用代码,例如Object或void*.
原因:如果您编写公共基类的通用代码,则会失去类型检查的好处.此外,可能需要从特殊基类派生类,这使得维护代码变得更加困难.
有人可以用代码示例来解释这个吗?
这不是一个普通基类型的概念.它是一个"对象类"的使用,所有东西都必须从编写代码,或者更糟糕的是编写代码,void*
然后对指针指向的内容进行假设,对指向其他类型的指针进行类型转换,并希望获得最佳结果.最好以容器为例.
实现容器方法的正确方法是使用模板.例如:
template<typename T> void List<T>::append(const T& obj);
Run Code Online (Sandbox Code Playgroud)
对于Object
基类,这意味着您放入容器中的任何内容都必须派生自Object
,因为所有容器方法都Object*
用于所述容器中的数据.所以你得到这样的方法:
void List::append(Object* obj);
Run Code Online (Sandbox Code Playgroud)
这里有两件坏事:首先,Object
无论你走到哪里,这个班都要随着你的容器被拖走.其次,它是一个可怕的通用名称,可能会与Object
其他库中的类冲突.
此外,您的容器永远不能包含不Object
直接派生的类型,包括基本类型int
和标准类型std::string
.您必须在Object
子类中"包装"这些类型,然后您必须花时间使用代码从这些包装器对象中提取值等.这是您不需要的后端的痛苦.
所以你可能认为你可以使用通用指针void*
代替:
void List::append(void* obj);
Run Code Online (Sandbox Code Playgroud)
但是当你这样做时,容器可能需要做很多事情,但事实并非如此,因为它不知道它void*
指向的是什么:
等等.(在Object*
虚拟方法的情况下,您可以避免这些问题,例如声明:
virtual ~Object() {}
virtual Object* clone() const;
virtual int cmp(const Object* rhs) const;
Run Code Online (Sandbox Code Playgroud)
必须由基类中的所有子类覆盖这些方法Object
.但现在你的Object
班级不是很轻便.)
在这两种情况下,对于容器的数据类型使用模板化类型会更好.如果您担心代码膨胀并且容器中的代码不关心数据类型(因为它不会打扰数据,例如计算包含的元素时),您可以将该代码放在基类中并让你的模板化容器类派生自它.但大多数时候没有人真正关心这种"臃肿",因为它比你的可用内存要小得多.
如果编写公共基类的通用代码,则会失去类型检查的好处.
既然你已经强制转换Object*
或void*
,类型检查出去大部分窗口.(注意:这有点过时了,因为在某些情况下你可以使用运行时类型识别(RTTI)和dynamic_cast
操作来执行类型检查,以确保从容器中取出的对象是你期望的类型.但是所有上述限制仍然适用,因为容器仍然不知道它包含什么.)