use*_*112 55 c++ polymorphism virtual pointers
我确实在SO上发现了一些类似标题的问题 - 但是当我读到答案时,他们关注的是问题的不同部分,这些部分是非常具体的(例如STL /容器).
有人可以告诉我为什么你必须使用指针/引用来实现多态?我可以理解指针可能会有所帮助 - 但肯定只能引用区分传值和传递参考?
当然,只要你在堆上分配内存 - 这样你就可以拥有动态绑定,那么这就足够了 - 显然不是.
Luc*_*ore 50
"当然只要你在堆上分配内存" - 分配内存与它无关.这都是关于语义的.举个例子:
Derived d;
Base* b = &d;
Run Code Online (Sandbox Code Playgroud)
d在堆栈(自动内存)上,但多态仍然可以工作b.
如果您没有基类指针或对派生类的引用,则多态性不起作用,因为您不再具有派生类.采取
Base c = Derived();
Run Code Online (Sandbox Code Playgroud)
该c物体是不是一个Derived,而是一个Base,因为切片.因此,从技术上讲,多态性仍然有效,只是你不再有一个Derived对象可以谈论.
现在拿走
Base* c = new Derived();
Run Code Online (Sandbox Code Playgroud)
c只是指向内存中的某个位置,你并不关心它是否真的是a Base或a Derived,但是对virtual方法的调用将动态解决.
Ste*_*Lin 47
在C++中,对象始终具有在编译时已知的固定类型和大小(如果它可以且确实具有其地址)在其生存期内始终存在于固定地址.这些是从C继承的功能,有助于使这两种语言适合低级系统编程.(所有这些都受到as-if规则的约束:符合标准的编译器可以随意使用代码做任何事情,只要它可以被证明对符合程序的任何行为都没有可检测的影响.按标准.)
甲virtual在C++函数被定义(或多或少,不需要极端语言律师业)作为执行基于对象的运行时类型; 当直接在一个对象上调用时,它将始终是该对象的编译时类型,因此当以virtual这种方式调用函数时,没有多态性.
请注意,这不一定是这种情况:带有virtual函数的对象类型通常在C++中实现,每个对象指向一个virtual函数表,每个类型都是唯一的.如果是这样倾斜的,用于C++的一些假设的变体的编译器可以执行关于对象(如分配Base b; b = Derived())作为复制对象的两个内容和virtual与它一起表指针,这将容易如果两个工作Base和Derived大小相同.在两者大小不同的情况下,编译器甚至可以插入暂停程序任意时间的代码,以便重新安排程序中的内存并以可能的方式更新对该内存的所有可能引用.被证明对程序的语义没有可检测的影响,如果没有找到这样的重新排列就终止程序:但这样效率非常低,并且不能保证永远停止,显然不是指定运算符所需的特征有.
因此,代替上述内容,C++中的多态性是通过允许引用和指向对象的引用并指向其声明的编译时类型及其任何子类型的对象来实现的.当virtual通过引用或指针调用函数,并且编译器无法证明引用或指向的对象是具有该virtual函数的特定已知实现的运行时类型时,编译器会插入查找正确virtual函数的代码叫一个运行时.它也不一定是这样的:引用和指针可能被定义为非多态的(不允许它们引用或指向它们声明的类型的子类型)并迫使程序员提出实现多态的替代方法.后者显然是可能的,因为它一直在C中完成,但在那时,没有太多理由要有一种新语言.
总而言之,C++的语义设计方式允许对面向对象的多态性进行高级抽象和封装,同时仍保留特性(如低级访问和内存显式管理),使其适用于低层次的发展.您可以轻松地设计一种具有其他语义的语言,但它不会是C++,并且会有不同的优点和缺点.
Ell*_*iot 12
我发现在分配这样的时候理解复制构造函数是非常有用的:
class Base { };
class Derived : public Base { };
Derived x; /* Derived type object created */
Base y = x; /* Copy is made (using Base's copy constructor), so y really is of type Base. Copy can cause "slicing" btw. */
Run Code Online (Sandbox Code Playgroud)
由于y是Base类的实际对象,而不是原始对象,因此调用的函数是Base的函数.