快速提问:从设计的角度来看,为什么在C ++中没有所有的基础类,object
而其他语言通常是什么?
typedef
s。对于更通用的类层次结构,您可以使用object
或iterator
。
快速提问:从设计的角度来看,为什么在C ++中没有所有的基础类,object
而其他语言通常是什么?
typedef
s。对于更通用的类层次结构,您可以使用object
或iterator
。
Answers:
最终裁定可在Stroustrup的FAQ中找到。简而言之,它不传达任何语义含义。这将需要费用。模板对于容器更有用。
为什么C ++没有通用类Object?
我们不需要一个:通用编程在大多数情况下提供了静态类型安全的替代方案。其他情况使用多重继承处理。
没有有用的通用类:真正的通用不带有其自身的语义。
“通用”类鼓励对类型和接口的草率思考,并导致过多的运行时检查。
使用通用基类意味着成本:必须对对象进行堆分配以使其具有多态性。这意味着内存和访问成本。堆对象自然不支持复制语义。堆对象不支持简单的作用域行为(这会使资源管理变得复杂)。通用基类鼓励使用dynamic_cast和其他运行时检查。
Objects must be heap-allocated to be polymorphic
-我认为这句话通常是不正确的。您绝对可以在堆栈上创建一个多态类的实例,并将其作为指向其基类之一的指针传递,从而产生多态行为。
Foo
为基准,TO-Bar
时,Bar
不继承Foo
,确定性引发异常。在C ++中,尝试将“指向Foo的指针”转换为“指向Bar的指针”可能会使机器人及时返回以杀死Sarah Connor。
首先让我们考虑一下为什么首先要具有基类。我可以想到一些不同的原因:
这是Smalltalk,Ruby和Objective-C品牌的语言具有基类的两个很好的理由(从技术上讲,Objective-C并不真正具有基类,但从所有意图和目的来看,它都有基类)。
对于#1,通过在C ++中包含模板避免了统一一个接口下所有对象的基类的需要。例如:
void somethingGeneric(Base);
Derived object;
somethingGeneric(object);
当您可以通过参数多态性完全保持类型完整性时,这是不必要的!
template <class T>
void somethingGeneric(T);
Derived object;
somethingGeneric(object);
对于#2,在Objective-C中,内存管理过程是类实现的一部分,并且是从基类继承的,而C ++中的内存管理是使用组合而不是继承来执行的。例如,您可以定义一个智能指针包装器,该包装器将对任何类型的对象执行引用计数:
template <class T>
struct refcounted
{
refcounted(T* object) : _object(object), _count(0) {}
T* operator->() { return _object; }
operator T*() { return _object; }
void retain() { ++_count; }
void release()
{
if (--_count == 0) { delete _object; }
}
private:
T* _object;
int _count;
};
然后,您将在其包装器中调用方法,而不是在对象本身上调用方法。这不仅允许进行更通用的编程:还使您可以分开关注(因为理想情况下,对象应更关注对象应该做什么,而不是在不同情况下应如何管理其内存)。
最后,在一种既具有原语又具有诸如C ++之类的实际对象的语言中,拥有基类(对于每个)中,失去值都有),因为那样的话,您将拥有某些不符合该接口的值。为了在这种情况下使用原语,您需要将它们提升到对象中(如果编译器不会自动执行)。这造成很多复杂性。
因此,对于您的问题的简短答案是:C ++没有基类,因为通过模板具有参数多态性,它不需要。
object
(System.Object
),但他们并不需要的人。编译器,int
以及System.Int32
是别名和可以互换使用; 运行时在需要时处理装箱。
std::shared_ptr
应该使用C ++ 11代替。
C ++变量的主要范例是按值传递,而不是按引用传递。强制一切都从根派生Object
将使按值传递它们成为事实错误。
(因为接受按值作为参数的对象,将按定义对其进行切片并删除其灵魂)。
这是不受欢迎的。C ++让您考虑是想要值还是引用语义,从而给您选择的余地。这是性能计算中的一件大事。
Object
相对较小。
问题是C ++中有这种类型!是的void
。:-)任何指针都可以安全地隐式转换为void *
,包括指向基本类型,没有虚拟表的类和具有虚拟表的类的指针。
由于它应该与所有这些类别的对象兼容,因此它void
本身不能包含虚拟方法。如果没有虚拟函数和RTTI,则无法从类型中获取有用的信息void
(它与EVERY类型匹配,因此只能说出对每种类型都适用的事实),但是虚拟函数和RTTI会使简单类型变得非常无效,并且会阻止C ++成为现实。适用于具有直接内存访问等功能的低级编程的语言。
因此,有这种类型。由于语言的低级性质,它仅提供了非常简约的接口(实际上是空的)。:-)
void
。
void
是一种类型(并发现了巧妙的用法? :
),但距离成为通用基类还有很长的路要走。一方面,它是“无法完成的不完整类型”,另一方面,它是没有void&
类型的。
C ++是一种强类型的语言。但是令人困惑的是,在模板专业化的情况下,它没有通用的对象类型。
以模式为例
template <class T> class Hook;
template <class ReturnType, class ... ArgTypes>
class Hook<ReturnType (ArgTypes...)>
{
...
ReturnType operator () (ArgTypes... args) { ... }
};
可以实例化为
Hook<decltype(some_function)> ...;
现在,假设我们希望为特定功能使用相同的功能。喜欢
template <auto fallback> class Hook;
template <auto fallback, class ReturnType, class ... ArgTypes>
class Hook<ReturnType fallback(ArgTypes...)>
{
...
ReturnType operator () (ArgTypes... args) { ... }
};
用专门的实例化
Hook<some_function> ...
但是可惜的是,即使在专业化之前T类可以代表任何类型(无论是否具有类),也没有任何等效项auto fallback
(在这种情况下,我使用该语法作为最明显的通用非类型)。专业化之前的非类型模板参数。
因此,通常这种模式不会从类型模板参数转换为非类型模板参数。
就像在C ++语言中遇到很多麻烦一样,答案很可能是“没有委员会成员想到它”。
ReturnType fallback(ArgTypes...)
可以使用,也可能是错误的设计。template <class T, auto fallback> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...), ReturnType(*fallback)(ArgTypes...)> ...
做您想要的并且意味着其模板参数Hook
是一致的种类
C ++最初被称为“带有类的C”。它是C语言的一种进步,与其他一些更现代的事物(例如C#)不同。而且您不能将C ++视为一种语言,而是将其视为语言的基础(是的,我还记得Scott Meyers撰写的《有效C ++》)。
C本身是语言,C编程语言及其预处理器的混合。
C ++增加了另一种组合:
类/对象方法
范本
STL
我个人不喜欢直接从C到C ++的某些东西。枚举功能就是一个例子。C#允许开发人员使用它的方式更好:它将枚举限制在其自己的范围内,它具有Count属性,并且很容易迭代。
由于C ++希望与C兼容,因此设计师允许C语言将其整体输入C ++(有些细微的差异,但是我不记得使用C编译器可以做的任何事情,无法使用C ++编译器)。