...
This code example is non-compliant because of the unintended data loss.
Code Block | ||||
---|---|---|---|---|
| ||||
class Employee { public: Employee(string theName) : name(theName) {}; string getName() const {return name;} virtual void print() const { cout << "Employee: " << getName() << endl; } private: string name; }; class Manager : public Employee { public: Manager(string theName, Employee theEmployee) : Employee(theName), assistant(theEmployee) {}; Employee getAssistant() const {return assistant;} virtual void print() const { cout << "Manager: " << getName() << endl; cout << "Assistant: " << assistant.getName() << endl; } private: Employee assistant; }; int main () { Employee coder("Joe Smith"); Employee typist("Bill Jones"); Manager designer("Jane Doe", typist); coder = designer; // slices Jane Doe! coder.print(); } |
...
Assuming exactly the same class structure as above, if pointers to the objects are used so that objects are copied by reference, then slicing does not occur.
Code Block | ||||
---|---|---|---|---|
| ||||
int main () { Employee *coder = new Employee("Joe Smith"); Employee *typist = new Employee("Bill Jones"); Manager *designer = new Manager("Jane Doe", *typist); coder = designer; coder->print(); } |
...
Alternatively, it is often safer to use a smart pointer, like std::auto_ptr, to hold the address of allocated memory. This is typically more robust than the use of raw pointers.
Code Block | ||||
---|---|---|---|---|
| ||||
int main () { auto_ptr<Employee> coder( new Employee("Joe Smith") ); auto_ptr<Employee> typist( new Employee("Bill Jones") ); auto_ptr<Manager> designer( new Manager("Jane Doe", *typist) ); coder = designer; // Smith deleted, Doe xferred coder->print(); // everyone deleted } |
...
Alternatively, references may be used to refer to the various derived employee objects.
Code Block | ||||
---|---|---|---|---|
| ||||
int main () { Employee coder("Joe Smith"); Employee typist("Bill Jones"); Manager designer("Jane Doe", typist); Employee &toPrint = designer; // Jane remains entire toPrint.print(); } |
...
The most effective way to avoid slicing of objects is to ensure, whenever possible, that polymorphic base classes are abstract.
Code Block | ||||
---|---|---|---|---|
| ||||
class Employee { public: Employee(string theName) : name(theName) {}; virtual ~Employee(); string getName() const {return name;} virtual void print() const = 0; private: string name; }; |
...