Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Coding style conformance

...

Code Block
bgColor#FFCCCC
langcpp
#include <iostream>
#include <string>

class Employee {
  std::string Namename;
  
protected:
  virtual void print(std::ostream &OSos) const {
    OSos << "Employee: " << getNameget_name() << std::endl;      
  }
  
public:
  Employee(const std::string &Namename) : Namename(Namename) {}
  const std::string &getNameget_name() const { return Namename; }
  friend std::ostream &operator<<(std::ostream &OSos, const Employee &Ee) {
    Ee.print(OSos);
    return OSos;
  }
};
 
class Manager : public Employee {
  Employee Assistantassistant;
  
protected:
  void print(std::ostream &OSos) const override {
    OSos << "Manager: " << getNameget_name() << std::endl;
    OSos << "Assistant: " << std::endl << "\t" << getAssistantget_assistant() << std::endl;      
  }
  
public:
  Manager(const std::string &Namename, const Employee &Assistantassistant) : Employee(Namename), Assistantassistant(Assistantassistant) {}
  const Employee &getAssistantget_assistant() const { return Assistantassistant; }
};

void f(Employee Ee) {
  std::cout << Ee;    
}

int main() {
  Employee Codercoder("Joe Smith");
  Employee Typisttypist("Bill Jones");
  Manager Designerdesigner("Jane Doe", Typisttypist);
  
  f(Codercoder);
  f(Typisttypist);
  f(Designerdesigner);
}

When f() is called with the Designer designer argument, the formal parameter in f() is sliced and information is lost. When the Employee object is printed, Employee::Printprint() is called instead of Manager::Printprint(), resulting in the following output:

...

Code Block
bgColor#ccccff
langcpp
void f(const Employee *Ee) {
  if (Ee) {
    std::cout << *Ee;
  }
}

int main() {
  Employee Codercoder("Joe Smith");
  Employee Typisttypist("Bill Jones");
  Manager Designerdesigner("Jane Doe", Typisttypist);
  
  f(&Codercoder);
  f(&Typisttypist);
  f(&Designerdesigner);
}

This compliant solution also complies with EXP34-C. Do not dereference null pointers in the implementation of f(). With this definition, the output becomes

...

Code Block
bgColor#ccccff
langcpp
void f(const Employee &Ee) {
  std::cout << Ee;
}

int main() {
  Employee Codercoder("Joe Smith");
  Employee Typisttypist("Bill Jones");
  Manager Designerdesigner("Jane Doe", Typisttypist);
  
  f(Codercoder);
  f(Typisttypist);
  f(Designerdesigner);
}

Compliant Solution (Noncopyable)

...

Code Block
bgColor#ccccff
langcpp
#include <iostream>
#include <string>

class Noncopyable {
  Noncopyable(const Noncopyable &) = delete;
  void operator=(const Noncopyable &) = delete;
  
protected:
  Noncopyable() = default;
};

class Employee : Noncopyable {
  std::string Namename;
  
protected:
  virtual void print(std::ostream &OSos) const {
    OSos << "Employee: " << getNameget_name() << std::endl;      
  }
  
public:
  Employee(const std::string &Namename) : Namename(Namename) {}
  const std::string &getNameget_name() const { return Namename; }
  friend std::ostream &operator<<(std::ostream &OSos, const Employee &Ee) {
    Ee.print(OSos);
    return OSos;
  }
};
 
class Manager : public Employee {
  const Employee &Assistantassistant; // Note: This definition has been modified
  
protected:
  void print(std::ostream &OSos) const override {
    OSos << "Manager: " << getNameget_name() << std::endl;
    OSos << "Assistant: " << std::endl << "\t" << getAssistantget_assistant() << std::endl;      
  }
  
public:
  Manager(const std::string &Namename, const Employee &Assistantassistant) : Employee(Namename), Assistantassistant(Assistantassistant) {}
  const Employee &getAssistantget_assistant() const { return Assistantassistant; }
};
 
// If f() were declared as accepting an Employee, the program would be
// ill-formed because Employee cannot be copy-initialized.
void f(const Employee &Ee) {
  std::cout << Ee;    
}

int main() {
  Employee Codercoder("Joe Smith");
  Employee Typisttypist("Bill Jones");
  Manager Designerdesigner("Jane Doe", Typisttypist);
  
  f(Codercoder);
  f(Typisttypist);
  f(Designerdesigner);
}

Noncompliant Code Example

...

Code Block
bgColor#FFCCCC
langcpp
// In addition to the #includes from the previous example
#include <vector>
 
void f(const std::vector<Employee> &Vv) {
  for (const auto &Ee : Vv) {
    std::cout << Ee;
  }
}

int main() {
  Employee Typisttypist("Joe Smith");
  std::vector<Employee> Vv{Typisttypist, Employee("Bill Jones"), Manager("Jane Doe", Typisttypist)};
  f(Vv);
}

Compliant Solution

This compliant solution stores std::unique_ptr smart pointers in the std::vector, which eliminates the slicing problem:

Code Block
bgColor#ccccff
langcpp
// In addition to the #includes from the previous example
#include <memory>
#include <vector>

void f(const std::vector<std::unique_ptr<Employee>> &Vv) {
  for (const auto &Ee : Vv) {
    std::cout << *Ee;
  }
}

int main() {
  std::vector<std::unique_ptr<Employee>> Vv;
  
  Vv.emplace_back(new Employee("Joe Smith"));
  Vv.emplace_back(new Employee("Bill Jones"));
  Vv.emplace_back(new Manager("Jane Doe", *Vv.front()));
  
  f(Vv);
}

Risk Assessment

Slicing results in information loss, which could lead to abnormal program execution or denial-of-service attacks.

...