12
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
  • 918
  • 1
  • 11
  • 22
  • 1
    As a note, code like `Material strange = Unusual_Material();` can result in the object slicing problem: http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – wkl Nov 17 '10 at 20:54

2 Answers2

22

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; 
} 
Community
  • 1
  • 1
In silico
  • 51,091
  • 10
  • 150
  • 143
  • 1
    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! – user487100 Nov 17 '10 at 20:53
  • 1
    @user487100: That's okay, as long as you realize what went wrong. I do recommend that you pick up [a good C++ book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) though, as it will cover this fundamental topic in much greater detail. – In silico Nov 17 '10 at 20:56
  • 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. – user487100 Nov 17 '10 at 20:59
  • @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 Nov 17 '10 at 21:04
  • @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. – In silico Nov 17 '10 at 21:05
  • Yeah. Man, I would have absolutely banged my head into the table trying to figure out a bug resulting from slicing. – user487100 Nov 17 '10 at 21:07
  • @user487100: Again, I highly suggest that you pick up [a C++ book as recommended by the Stack Overflow C++ community](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) 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. – In silico Nov 17 '10 at 21:10
1

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;
}