我认为我理解虚方法和vtable的概念,但我不明白为什么将对象作为指针(或引用)传递并通过值传递(将哪种方式丢弃vtable或什么?)
为什么这样的事情有效:
Material* m = new Texture;
poly->setMaterial(m);
// methods from Texture are called if I keep carrying the pointer around
而不是这个?:
Material m = Texture();
poly->setMaterial(m);
// methods from Material are called if I pass the value around
答案 0 :(得分:17)
因为如果你传递值,那么object slicing将会发生,并且无法实现运行时多态性。在您的代码中,行Material m = Texture()
导致对象切片。因此,即使您通过指针(或引用)传递m
,也无法实现运行时多态性。
此外,运行时多态性是通过以下方式实现的:
因此,如果你想要运行时多态性,你可以使用基类型的指针或引用,这里有几个例子可以实现运行时多态性:
Material* m1 = new Texture();
poly->setMaterial(m1); //achieved
Texture* t1= new Texture();
poly->setMaterial(t1); //achieved
Texture t2;
poly->setMaterial( &t2); //achieved : notice '&'
Material & m2 = t2;
poly->setMaterial( &m2 ); //achieved : notice '&'
Material m3;
poly->setMaterial( &m3 ); //NOT achieved : notice '&'
仅在最后一行中您没有实现运行时多态性。
答案 1 :(得分:4)
Material m = Texture()
会调用构造函数Material::Material(Texture const &)
,或者,如果不可用,则调用Material
复制构造函数,构造Material
而不是Texture
这无法为您构建Texture
对象,因此该对象切片到基类对象。
答案 2 :(得分:3)
虚拟函数在两个示例中都能很好地工作。他们的工作方式完全符合预期。
虚函数的整体思想是根据调用中使用的对象的 dynamic 类型调度对此类函数的调用。 (很遗憾,您没有在示例中显示如何进行这些调用。)
在第一个示例中,您创建了一个Texture
类型的对象。对象的动态类型为Texture
,因此虚拟调用将转到Texture
的方法。
在第二种情况下,您将创建一个Material
类型的对象。对象的动态类型为Material
,因此虚拟调用将转到Material
的方法。
这就是它的全部。一切都按照人们的预期运作。如果你的期望与此不同,那么你应该让它们更好地与语言保持一致。
答案 3 :(得分:2)
因为Material m = Texture();
对对象进行切片 - 此时,您只有一个Material
。
答案 4 :(得分:1)
将“纹理”对象指定给“材质”后,会将其切割为“材质”。因此,对m对象的任何调用都只会调度Material函数。
Material m
只有一个Material对象的空间。
使用普通结构,我说明了切片的含义:
struct A {
int a;
};
struct B : public A {
int b;
};
A objectA = B();
objectA.b = 1; // compile error, objectA does only have the properties of struct A
答案 5 :(得分:1)
Material m = Texture();
这会创建一个临时Texture
,然后通过复制Material
的{{1}}部分来创建Material
。这称为切片,通常不是您想要的。
答案 6 :(得分:1)
class Base
{
//Members
};
class Derived1:public Base
{
//Members
};
int main()
{
Base obj1;
Derived1 obj2;
obj1 = obj2; //Allowed Since Public Inheritance
}
当obj1 = obj2
仅将从Base Class继承的Derived Class obj2的成员复制到obj1时,Derived Class的其余成员将被切掉。这只是因为Base类obj1不知道Derived类的成员。这个现象被称为Object Slicing
。
在您的情况下,当您致电Material m = Texture()
时,只包含Material
的成员,因此对象上的任何函数调用都会调用Material
&的成员函数。不是Texture
。