Why do virtual functions need to be passed with a pointer and not by value(of the object)?

拜拜、爱过 提交于 2019-11-30 13:54:07

Because if you pass by value, then object slicing will occur, and runtime polymorphism cannot be achieved. And in your code, the very line Material m = Texture() causes object slicing. So even if you pass m by pointer (or reference), runtime polymorphism cannot be achieved.

Also, runtime polymorphism is achieved through:

  • pointer of base type, or
  • reference of base type

So if you want runtime polymorphism, you've use either pointer or reference of base type, and here are few examples how you can achieve runtime polymorphism:

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 '&'

Only in the last line you don't achieve runtime polymorphism.

Material m = Texture() would call the constructor Material::Material(Texture const &), or, if that's not available, the Material copy constructor, which construct a Material rather than a Texture.

There is no way this can build a Texture object for you, so the object is sliced to a base class object.

Virtual functions works perfectly well in both of your examples. They work exactly as they are supposed to work.

The whole idea of a virtual function is that an call to such function is dispatched in accordance with the dynamic type of the object used in the call. (Unfortunately, you didn't show in your examples how you make these calls.)

In your first example, you created an object of type Texture. The dynamic type of the object is Texture, so the virtual calls go to the methods of Texture.

In the second case you create an object of type Material. The dynamic type of the object is Material, so the virtual calls go to the methods of Material.

That's all there is to it. Everything works just as one would expect. If your expectations are different from this, then you should just bring them in better alignment with the language.

Because Material m = Texture(); slices the object - at this point, you just have a Material.

Once you assign a Texture objecto to a Material, it is sliced to a Material. Therefore, any call on the m Object will dispatch only the Material functions.

Material m has space for exactly one Material object.

Using plain structs, I illustrate what is meant by slicing:

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
Material m = Texture();

This create a temporary Texture, then creates a Material by copying the Material part of Texture. This is called slicing, and is typically not what you want.

class Base
{
    //Members       
};

class Derived1:public Base
{
    //Members
};

int main()
{
    Base obj1;
    Derived1 obj2;

    obj1 = obj2;   //Allowed Since Public Inheritance 
}

When obj1 = obj2 only those members of the Derived Class obj2 that are inherited from Base Class get copied in to obj1, rest of the members of Derived Class get sliced off. This is simply because Base class obj1 is not aware of members of Derived class. This phenomemon is called Object Slicing.

In your case, when you call Material m = Texture() only contains members of Material and hence any function call on the object calls member functions of Material& not Texture.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!