开发者

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

开发者 https://www.devze.com 2023-03-01 03:22 出处:网络
I think I understand the concept开发者_如何学Python of virtual methods and vtables, but I don\'t understand why there is a difference between passing the object as a pointer(or reference) and passing

I think I understand the concept开发者_如何学Python of virtual methods and vtables, but I don't understand why there is a difference between passing the object as a pointer(or reference) and passing it by value (which kind of scraps the vtable or something?)

Why would something like this work:

Material* m = new Texture;
poly->setMaterial(m); 
// methods from Texture are called if I keep carrying the pointer around

And not this?:

Material m = Texture();
poly->setMaterial(m);
// methods from Material are called if I pass the value around


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.


based on c++ primer P604, virtual function could be resolved on run time once call is made through reference or pointer.

in example code on book

Bulk_quote derived("xxx",50,5,.19);
print_total(cout, derived, 10);

print_total is declared as

double print_total(ostream &os, const Quote &item, size_t n){
/*definition*/
}

the item here is passed through reference so it still calls the virtual function in derived class.

so in your case, I think if your setMaterial function get a Material reference parameter, it could still call Texture virtual function.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号