Call derived class method from base class reference

17,312

Solution 1

What you want is polymorphism, and to enable it for a function you need to make it virtual:

class Material 
{ 
public: 
    virtual void foo() // Note virtual keyword!
    { 
        cout << "Class Material"; 
    } 
}; 

class Unusual_Material : public Material 
{ 
public: 
    void foo() // Will override foo() in the base class
    { 
        cout << "Class Unusual_Material"; 
    } 
}; 

Also, polymorphism only works for references and pointers:

int main()  
{  
    Unusual_Material unusualMaterial;
    Material& strange = unusualMaterial;
    strange.foo();  
    return 0; 
}

/* OR */

int main()  
{  
    Unusual_Material unusualMaterial;
    Material* strange = &unusualMaterial;
    strange->foo();  
    return 0; 
}

What you have in your code snippet will slice the Unusual_Material object:

int main() 
{ 
    // Unusual_Material object will be sliced!
    Material strange = Unusual_Material(); 
    strange.foo(); 
    return 0; 
} 

Solution 2

Still better explanation would be..

class Base
{
public:
 void foo()     //make virtual void foo(),have derived method invoked
 {
  cout << "Class Base";
 }
};
class Derived: public Base
{
public:
 void foo()
 {
  cout << "Class Derived";
 }
};
int main()
{
 Base base1 = Derived ();
 Base1.foo(); //outputs "Class Base" 
           // Base object, calling base method

 Base *base2 = new Derived ();
 Base2->foo(); //outputs"Class Base",Again Base object calling base method

// But to have base object, calling Derived method, following are the ways
// Add virtual access modifier for base foo() method. Then do as below, to //have derived method being invoked.
//
// Base *base2 = new Derived ();
// Base2->foo();    //outputs "Class Derived" .

return 0;
}
Share:
17,312
user487100
Author by

user487100

Updated on June 14, 2022

Comments

  • user487100
    user487100 about 2 years
    class Material
    {
    public:
     void foo()
     {
      cout << "Class Material";
     }
    };
    
    class Unusual_Material : public Material
    {
    public:
     void foo()
     {
      cout << "Class Unusual_Material";
     }
    };
    
    int main()
    {
     Material strange = Unusual_Material();
     strange.foo(); //outputs "Class Material" 
    
     return 0;
    }
    

    I would like for this to result in the "Class Unusual_Material" being displayed to the console. Is there a way I can achieve this? In my program I have a class Material from which other more specific materials are derived. The method Material::foo() represents a method in Material that is adequate for most materials, but occationally, another foo() needs to be defined for a material with unusual properties.

    All objects in my program contain a Material field. In the event that they are assigned an unusual material, I would like the derived, unusual foo to be called.

    This is probably either pretty easy, or impossible, but I can't figure it out either way.

    Thanks

  • user487100
    user487100 over 13 years
    Ah! thank you for pointing that out. I guess I forgot that virtual was for more than defining an abstract class. Thank you for the quick response!
  • In silico
    In silico over 13 years
    @user487100: That's okay, as long as you realize what went wrong. I do recommend that you pick up a good C++ book though, as it will cover this fundamental topic in much greater detail.
  • user487100
    user487100 over 13 years
    And I also had no clue about slicing. I thought that the program would just not have access to the derived parts, but I guess, when not using a reference, that that makes a lot of sense. Thanks for adding that bit at the end for my edification.
  • In silico
    In silico over 13 years
    @user487100: It has to do with the fact that you can't "fit" an object of a derived class into an object of a base class, since the derived class will almost always have more data members. In a way, you don't get access to the derived parts, because those derived parts have been chopped off so that the compiler can assign a derived class object to a base class object.
  • In silico
    In silico over 13 years
    @user487100: However, pointers and references are the same size no matter whether they're pointers to a derived class or a base class, so you get no slicing problems using pointers and references.
  • user487100
    user487100 over 13 years
    Yeah. Man, I would have absolutely banged my head into the table trying to figure out a bug resulting from slicing.
  • In silico
    In silico over 13 years
    @user487100: Again, I highly suggest that you pick up a C++ book as recommended by the Stack Overflow C++ community since it will cover this and more. This problem that you have encountered is fundamental to the language, therefore, it would be in your best interest to really understand it.