/
09 – Inheritance 3.1 Introduction to Inheritance and Class Hierarchies 09 – Inheritance 3.1 Introduction to Inheritance and Class Hierarchies

09 – Inheritance 3.1 Introduction to Inheritance and Class Hierarchies - PowerPoint Presentation

danika-pritchard
danika-pritchard . @danika-pritchard
Follow
346 views
Uploaded On 2020-01-14

09 – Inheritance 3.1 Introduction to Inheritance and Class Hierarchies - PPT Presentation

09 Inheritance 31 Introduction to Inheritance and Class Hierarchies 32 Member Function Overriding Member Function Overloading and Polymorphism 33 Abstract Classes Assignment and Casting in a Hierarchy ID: 772860

string class int computer class string computer int const inheritance tostring function laptop std public include private member data

Share:

Link:

Embed:

Download Presentation from below link

Download Presentation The PPT/PDF document "09 – Inheritance 3.1 Introduction to I..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

09 – Inheritance 3.1 Introduction to Inheritance and Class Hierarchies3.2 Member Function Overriding, Member Function Overloading, and Polymorphism3.3 Abstract Classes, Assignment, and Casting in a Hierarchy 1

Lab 02 - SNAP 2

S.N.A.P Lab Class design is type design - defining effective classes can be challenging.For the SNAP lab you are to design classes for a school database with has-a and is-a relationships that have natural syntax, intuitive semantics, and efficient memory allocation.The class objects are populated from parsed input strings.Use object inheritance, polymorphism, and function and operator overloading where needed.All member data and internal functions are private.All classes have a "toString" method with friends for the insertion ("<<") operator.Use UML diagrams to describe your implementation.Inheritance (9)3

Example SNAP Output Inheritance (9)4Input Strings:snap(12345,Charlie Brown,Manager,555-1234).snap(67890,Lucy,Right Field,555-5678).csg(CS101,12345,A).csg(CS101,67890,B).**Error: csgs(CS101,67890,B).cdh(CS101,M,9AM).cdh(CS101,W,9AM).cr(CS101,1170 TMCB).Vectors:snap(12345,Charlie Brown,Manager,555-1234)snap(67890,Lucy,Right Field,555-5678)csg(CS101,12345,A)csg(CS101,67890,B) cdh(CS101,M,9AM)cdh(CS101,W,9AM) cr (CS101,1170 TMCB) Course Grades: CS101,Charlie Brown,A CS101,Lucy,B Student Schedules: Charlie Brown, 12345, Manager, 555-1234 CS101 MW 9AM, 1170 TMCB Lucy, 67890, Right Field, 555-5678 CS101 MW 9AM, 1170 TMCB Student # NameAddressPhone # CourseStudent #Grade CourseDayHour CourseRoom Input Error List in csg order List in snap order List in csg order

Student # NameAddressPhone #CourseStudent #GradeCourseDayHourCourseRoom Input Error List in csg order List in snap order List in csg order

string toString() const { stringstream out; out << "snap(" << this->studentId; out << "," << this->studentName; out << "," << this->studentAddress; out << "," << this->studentPhone << ")"; return out.str();}friend std::ostream& operator<< (ostream& os, const Snap& snap){ os << snap.toString(); return os;} vector<Snap> snaps; vector< Csg > csgs ; vector< Cdh > cdhs ; vector<Cr> crs;

UML Inheritance (9)7This class is called Passenger.The data members are all listed by visibility, name, and type.Visibility: A '-' in front of a data member or function means that the data or function is private. A '+' indicates public visibility and a '#' indicates a protected visibilityType: You may indicate parameter type and return type before or after the name of the data member/function.Both of the following are acceptable: +string getName() +getName():stringClass NameData Members Class Methods Private Public

UML Inheritance (9)8This class is called Passenger.The data members are all listed by visibility, name, and type.Visibility: A '-' in front of a data member or function means that the data or function is private. A '+' indicates public visibility and a '#' indicates a protected visibilityType: You may indicate parameter type and return type before or after the name of the data member/function.Both of the following are acceptable: +string getName() +getName():string

UML Inheritance ("Is-a") Inheritance (9)9In this example, the class Steam Engine inherits from the abstract class Locomotive. It has access to all of the concrete functions of Locomotive, and also defines the abstract functions of Locomotive.Note that not all of the concrete functions from Locomotive are included in SteamEngine. This is because they are accessed through inheritance structure. On the other hand, the abstract functions appear in both places. It is a good practice to show a function both where it is declared and where it is defined.For the interfaces that you will use in this class, it is acceptable to omit the inherited functions from the child class.Inheritance is indicated with a white triangle arrowhead facing the parent class.

UML Inheritance ("Has-a") Inheritance (9)10In this example, the class Steam Engine references the class Passenger, placing pointers to Passenger objects inside of its private vector.This relationship is indicated by using a filled diamond arrow. The arrow faces towards the class that "has" the other thing in it.Note: For the purposes of our class, we do not distinguish between having an object and having a pointer to an object. Just use the same type of arrow.

SNAP Inheritance Inheritance (9)11SNAP-int studID-string name-string address-string phone+int getStudID() +string getName () +string getAddr () +string getPhone () +toString() const Student -int studID +int getStudID () +toString() const Csg -string course -int studID -string grade +string getCourse () +int getStudID () +string getGrade () +toString() const Cdh -string course -string day -string hour +string getCourse () +string getDay () +string getHour () +toString() const Cr -string course -string room +string getCourse () +string getRoom () +toString() const Course -string course +string getCourse () +toString() const

SNAP Inheritance Inheritance (9)12SNAP-int studID-string name-string address-string phone+int getStudID ()+string getName () +string getAddr () +string getPhone () +toString() const Student -int studID +int getStudID () +toString() const Csg -string course -int studID -string grade +string getCourse () +int getStudID () +string getGrade () +toString() const Course -string course +string getCourse () +toString() const Cdh -string course -string day -string hour +string getCourse () +string getDay () +string getHour () +toString() const Cr -string course -string room +string getCourse () +string getRoom () +toString() const This process is known as refactoring and is often used in object-oriented design.

3.1 Introduction to Inheritance and Class Hierarchies 3.1 Introduction to Inheritance and Class Hierarchies Is-a Versus Has-a Relationships A Base Class and a Derived ClassInitializing Data Fields in a Derived Class The No-Parameter ConstructorProtected Visibility for Base-Class Data Fields 15

Inheritance and Class Hierarchies Object-Oriented Programming (OOP) enables programmers to reuse previously written code saved as classes'Code reuse reduces the time required to code new applications'.Previously written tested and debugged code enables new applications to be more reliable. In OOP, a programmer can create a similar class by extending an existing class, rather than by writing an entirely new class.The new class (called the derived class or subclass) can have additional data fields and member functions.The derived class inherits the data fields and member functions of the original class (called the base class or superclass).multiple parents.Inheritance (9)16 A class hierarchy represents a set of hierarchically organized concepts. Base classes act typically as interfaces. Implementation inheritance Interface inheritance. If a base class is used as an interface, make it a pure abstract class.

Is-a Versus Has-a RelationshipsThe is-a relationship between classes means that every instance of one class is also an instance of the other class (but not the other way around).Inheritance (9)17 The has-a relationship between classes means that every instance of one class is or may be associated with one or more instances of the other. A jet airplane is an airplane, but not all airplanes are jet airplanes. The jet airplane class is derived from an airplane class. The is-a relationship is represented in object oriented programming by extending a class. For example, a jet plane has-a jet engine. The has-a relationship is represented by declaring in one class a data field whose type is another class.

Is-a Versus Has-a RelationshipsWe can combine is-a and has-a relationshipsA jet plane is an airplane, and it has a jet engineThe jet airplane inherits all the properties of an airplane. An airplane has a tail, so a jet plane does too because it is an airplane.C++ allows you to capture both the inheritance (is-a) relationship and the has-a relationship:class JetPlane : public Airplane{private: int num_engines; JetEngine jets[4]; // Jet planes may have 4 engines // ... }; The part of the class heading following the colon specifies that JetPlane is a derived class of Airplane Inheritance (9) 18 The JetEngine data field stores information for up to 4 jet engines for a JetPlane object.

A Base Class and a Derived Class 19Inheritance (9) A computer has a: manufacturer processor RAM disk Computer - manufacturer:string - processor:string - ramSize:int - diskSize:int + getRamSize () const:int + getDiskSize() const:int +toString() const:string LapTop - screenSize:int - weight:double + getScreenSize () const:int + getWeight () const:double We can define class LapTop as a derived class of class Computer . A laptop computer is a kind of computer, so it has all the properties of a computer plus some additional features: screen size weight "A LapTop is-a Computer"

Class Computer#ifndef COMPUTER_H_#define COMPUTER_H_#include <string>class Computer{private: std::string manufacturer; std::string processor; int ramSize ; int diskSize ; public: Computer(const std::string& man, const std::string& proc, int ram, int disk) : manufacturer(man), processor(proc), ramSize (ram), diskSize (disk) {} int getRamSize() const { return ramSize ; } int getDiskSize () const { return diskSize; } std::string toString() const;}; #endif #include " computer.h " #include < sstream > using std:: ostringstream ; using std::string; using std::endl; string Computer:: toString () const { ostringstream sb ; sb << "Manufacturer: " << manufacturer << endl << "CPU: " << processor << endl << "RAM: " << ramSize << " Mbs " << endl << "Disk: " << diskSize << " Gbs "; return sb.str (); } Computer.h Inheritance (9) 20 There are 4 private data elements common to all computers. Small in-line member functions are included in the .h file (<= 10 lines). Larger class implementations are often found in a corresponding . cpp file. Computer.cpp

Class LapTop#ifndef LAP_TOP_H#define LAP_TOP_H#include <string>#include <sstream>#include "computer.h"using std::string;using std::ostringstream; class LapTop : public Computer { private: int screenSize ; double weight; public: LapTop (const string& m, const string& p, int r, int d, int s, double w) : Computer(m, p, r, d) , screenSize (s), weight(w) {} int getScreenSize () const { return screenSize; } double getWeight() const { return weight; }}; #endif LapTop.h Inheritance (9) 21 Class LapTop is derived from class Computer and publicly inherits Computer 's data members and member functions. The constructor for class LapTop must begin by initializing the four data fields inherited from class Computer . Because those data fields are private to the base class, C++ requires that they be initialized by a base class constructor. In the definition of a constructor of a class, member initializer list specifies the initializers for direct and virtual base subobjects and non-static data members.

Protected Data Fields class Computer{private: std::string manufacturer; std::string processor; int ramSize; int diskSize;public: // ...}; class LapTop : public Computer { private: // ... public: void setManufacturer (std::string m) { manufacturer = m; } // ... }; Computer.h LapTop.hInheritance (9) 22 class Computer { protected: std::string manufacturer; private: std::string processor; int ramSize ; int diskSize ; public: // ... }; class LapTop : public Computer { private: // ... public: void setManufacturer (std::string m) { manufacturer = m; } // ... }; Illegal!! The data fields inherited from class Computer have private visibility—they can be accessed only within class Computer . C++ provides a less restrictive form of visibility called protected visibility to allow a derived class to directly access data fields declared in its base class

Public, Protected, Private Inheritance Inheritance (9)23class A {public: int x;protected: int y;private: int z;};class B : public A{ // x is public // y is protected // z is not accessible from B}; class C : protected A { // x is protected // y is protected // z is not accessible from C }; class D : private A { // x is private // y is private // z is not accessible from D }; 'private' is default for classes Classes B, C and D all contain the variables x, y and z. It is just question of access.

The No-Parameter Constructor If the execution of any constructor in a derived class does not invoke a base class constructor, C++ automatically invokes the no-parameter constructor for the base class.C++ does this to initialize the part of the object inherited from the base class before the derived class starts to initialize its part of the object.Inheritance (9)24

3.2, pgs. 193-203 3.2 Member Function Overriding, Member Function Overloading, and PolymorphismMember Function OverridingMember Function OverloadingVirtual Functions and Polymorphism 25

Review Inheritance (9)26#ifndef COMPUTER_H_#define COMPUTER_H_#include <string>#include <sstream>using std::ostringstream;using std::string;using std::endl;class Computer{private: string manufacturer; string processor; int ramSize; int diskSize ; public: Computer(const string& m, const string& p, int r, int d) : manufacturer(m), processor(p), ramSize (r), diskSize (d) {} int getRamSize () const { return ramSize; } int getDiskSize() const { return diskSize; } string toString() const { ostringstream sb; sb << "Manufacturer: " << manufacturer << endl << "CPU: " << processor << endl << "RAM: " << ramSize << " Mbs" << endl << "Disk: " << diskSize << " Gbs"; return sb.str();}}; #endif#ifndef LAP_TOP_H #define LAP_TOP_H#include <string>#include <sstream> #include " computer.h " using std::string; using std:: ostringstream ; class LapTop : public Computer { private: int screenSize ; double weight; public: LapTop (const string& m, const string& p, int r, int d, int s, double w) : Computer(m, p, r, d), // init Computer screenSize (s), weight(w) {} // init LapTop int getScreenSize () const { return screenSize ; } double getWeight () const { return weight; } }; #endif The constructor for class Lap_Top must begin by initializing the four data fields inherited from class Computer . Because those data fields are private to the base class, C++ requires that they be initialized by a base class constructor

Member Function Overriding #include <iostream>#include <string>#include "lapTop.h"using namespace std;int main(int argc, char* argv[]){ Computer myComputer("HP", "I5", 16, 500); LapTop yourComputer ("Dell", "I7", 32, 1000, 15, 5); cout << endl << "My computer:" << endl << myComputer.toString () << endl; cout << endl << "Your computer:" << endl << yourComputer.toString () << endl; return 0;} Inheritance (9)27 My computer:Manufacturer: HP CPU: I5RAM: 16 Mbs Disk: 500 Gbs Your computer:Manufacturer: DellCPU: I7RAM: 32 Mbs Disk: 1000 Gbs Even though yourComputer is of type LapTop , the LapTop fields are not displayed; the call to toString () calls the toString () method inherited from Computer Class LapTop have does not have a toString method.

Member Function Overriding #ifndef LAP_TOP_H#define LAP_TOP_H#include <string>#include <sstream>#include "computer.h"using std::string;using std::ostringstream;class LapTop : public Computer { private: int screenSize ; double weight; public: LapTop (const string& m, const string& p, int r, int d, int s, double w) : Computer(m, p, r, d), screenSize(s), weight(w) {} int screenSize() const { return screenSize; } double getWeight() const { return weight; } string toString() const;}; #endif #include " lapTop.h " #include < sstream > using std:: ostringstream ; using std::string; using std::endl; string LapTop :: toString () const { ostringstream sb ; sb << Computer:: toString () << endl << "Screen: " << screenSize << " inches" << endl << "Weight: " << weight << " lbs "; return sb.str (); } LapTop.h Inheritance (9) 28 If class LapTop has its own toString member function, it will override the inherited member function and will be invoked by the member function call to toString(). LapTop.cpp We still call Computer 's toString member function to output its contents.

Member Function Overriding #include <iostream>#include <string>#include "lapTop.h"using namespace std;int main(int argc, char* argv[]){ Computer myComputer("HP", "I5", 16, 500); LapTop yourComputer ("Dell", "I7", 32, 1000, 15, 5); cout << endl << "My computer:" << endl << myComputer.toString () << endl; cout << endl << "Your computer:" << endl << yourComputer.toString () << endl; return 0;} Inheritance (9)29 My computer:Manufacturer: HP CPU: I5RAM: 16 Mbs Disk: 500 Gbs Your computer:Manufacturer: DellCPU: I7RAM: 32 Mbs Disk: 1000 Gbs Screen: 15 inches Weight: 5 lbs Now the state of a laptop computer, complete with screen size and weight, is output when calling toString member function for class LapTop which overrides the inherited member function of Computer .

Virtual Functions and Polymorphism #include <iostream>#include <vector>#include <string>#include "lapTop.h"using namespace std;int main(int argc, char* argv[]){ vector<Computer*> computers; computers.push_back (new Computer("Acer", "I3", 8, 256)); computers.push_back (new LapTop ("HP", "I5", 16, 500, 13, 6.5)); for (unsigned int i = 0; i < computers.size(); i ++) cout << endl << computers[i ]->toString() << endl; return 0; }Inheritance (9) 30 Manufacturer: AcerCPU: I3RAM: 8 Mbs Disk: 256 Gbs Manufacturer: HP CPU: I5 RAM: 16 Mbs Disk: 500 Gbs In C++, a pointer variable of a base-class type (general) can point to an object of a derived-class type (specific): LapTop objects are Computer objects with more features. But, where are the additional data members??

Virtual Functions and Polymorphism #include <iostream>#include <vector>#include <string>#include "lapTop.h"using namespace std;int main(int argc, char* argv[]){ vector<Computer*> computers; computers.push_back (new Computer("Acer", "I3", 8, 256)); computers.push_back (new LapTop ("HP", "I5", 16, 500, 13, 6.5)); for (unsigned int i = 0; i < computers.size(); i ++) cout << endl << computers[i ]->toString() << endl; return 0; }Inheritance (9) 31 Manufacturer: AcerCPU: I3RAM: 8 Mbs Disk: 256 Gbs Manufacturer: HP CPU: I5 RAM: 16 Mbs Disk: 500 Gbs Screen: 13 inches Weight: 6.5 lbs By changing the declaration of the function toString in the class Computer (in Computer.h ) to a virtual function, when it is called through a pointer (or reference) variable the actual member function will be determined at run time and based on the type of the object pointed to (or referenced). class Computer { // ... public: // ... virtual string toString() const; };

class Computer { // ... public: // ... string toString() const; }; class LapTop : public Computer { // ... public: // ... string toString() const; }; int main() { vector<Computer*> computers; computers.push_back(new Computer(...)); computers.push_back(new LapTop(...)); cout computers[1]->toString();} Polymorphism is an important concept of OOP. Polymorphism is the quality of having many forms or many shapes. Polymorphism enables the program to determine which member function to invoke at run time . Inheritance (9) 32 Virtual Functions and Polymorphism class Computer { // ... public: // ... virtual string toString() const; }; class LapTop : public Computer { // ... public: // ... virtual string toString() const; }; int main() { vector<Computer*> computers; computers.push_back (new Computer(...)); computers.push_back (new LapTop (...)); cout computers[1]->toString(); } At compile time, the C++ compiler cannot determine what type of object computers will point to. At run time, polymorphism and virtual functions allows the program to know which toString function to call. Use pointers to your objects. Declare the function in base class virtual. BTW: It is good practice to include the virtual declaration in the derived classes too for documentation purposes.

3.3, pgs. 203-206 3.3 Abstract Classes, Assignment, and Casting in a HierarchyReferencing Actual ObjectsSummary of Features of Actual Classes and Abstract ClassesAssignments in a Class HierarchyCasting in a Class Hierarchy Case Study: Displaying Addresses for Different Countries 33

Abstract Classes An abstract class differs from an actual class (sometimes called a concrete class) in two respects:An abstract class cannot be instantiated.An abstract class declares at least one abstract member function, which must be defined in its derived classes.An abstract function is a virtual function that is declared but for which no body (definition) is provided.We use an abstract class in a class hierarchy whenA base class can define attributes and functions that are common to derived classes.Actual derived classes may have unique as well as shared implementations. Pure abstract functions must be defined by derived concrete classes.Inheritance (9)34

Abstract Class Food.h#ifndef FOOD_H_#define FOOD_H_class Food{private:double calories;public:virtual double percent_protein() const = 0; virtual double percent_fat () const = 0 ; virtual double percent_carbohydrates () const = 0 ; double get_calories () const { return calories; }void set_calories (double cal) { calories = cal ; }}; #endif These three abstract virtual functions impose the requirement that all derived classes implement these functions.(We would expect a different function definition for each kind of food.)Inheritance (9) 35 A pure virtual function is specified in the class definition by using "= 0;:" in place of the function body.

Referencing Concrete Objects Because class Food is abstract, we can’t create type Food objects, hence the following statement is invalid: Food mySnack(); // compile time error!We can use a type Food pointer variable to point to an actual object that belongs to a class derived from Food.If a Vegetable object is derived from Food, then Food is contained in Vegetable.Inheritance (9) 36 Thus a pointer to Food can be used to reference a Vegetable . The pointer variable mySnack (type pointer-to- Food ) is legal: Food* mySnack = new Vegetable("carrot sticks"); Vegetable Food

Assignments in a Class Hierarchy C++ is what is known as a strongly typed language.Operands have a type, and operations can be performed only on operands of the same or compatible types.This includes the assignment operation: l-value = r-value For the built-in types the r-value must be of the same type as the l-value, or there must be a conversion defined to convert the r-value into a value that is the same type as the l-value.For class types, the assignment operator may be overridden and overloaded.Pointer types are an exception: A pointer variable (l-value) that is of type pointer-to-base class may point to a derived object (r-value).However, the opposite is not legal:Computer* computer = new LapTop( ... ); // LegalLapTop* laptop = new Computer( ... ); // IllegalInheritance (9) 37

Attendance Quiz #9 Inheritance (9)38

40

3.4, pgs. 210-212 3.4 Multiple InheritanceRefactoring the Employee and Student Classes 41

Multiple Inheritance Multiple inheritance refers the ability of a class to extend more than one class.In multiple inheritance, all the data fields for the derived class are inherited from its base classes.For example, a university has many students who are full-time students and many employees who are full-time employees, but also some student employees.Inheritance (9)42

Definition of Student_Worker#ifndef STUDENT_WORKER_H_#define STUDENT_WORKER_H_#include <string>#include "Employee.h"#include "Student.h"class StudentWorker : public Employee, public Student{public: Student_Worker(const std::string& name,Address* address,double rate,const std::string& major) : Employee(name, address, rate), Student(name, address, major) {} std::string to_string() const; }; #endif Inheritance (9) 43 The heading shows that class StudentWorker extends class Employee and class Student The constructor contains two initialization expressions separated by a comma The first initializes the Employee part The second initializes the Student part There is no argument given for data fields hours or gpa , so they are initialized to default values

3.5, pgs. 212-220 3.5 Namespaces and VisibilityNamespacesDeclaring a NamespaceThe Global NamespaceThe using Declaration and using DirectiveUsing Visibility to Support Encapsulation The friend Declaration 44

typedef typedef is a C/C++ keyword used to create an alias name for another data type.typedef is helpful for giving a short, unambiguous alias to a portable data structure or a complicated function pointer type:Inheritance (9)45typedef unsigned int size_t;typedef list<string> MyList;typedef MyList::iterator MyListIterator ;MyList animals; MyListIterator iter = animals.begin (); Typedefs provide a level of abstraction away from the actual types being used, allowing you to focus more on the concept of just what a variable should mean. This makes it easier to write clean code, as well as make it far easier to modify your code.

typedef vs Using With C++11, you can use using to create a type alias.The identifier following the using keyword becomes a typedef-name.using has the same semantics as if it were introduced by the typedef specifier.For example:Inheritance (9)46 In general, if you're using a C++11 compiler, you should consider using the ' using ' syntax instead of typedefs. typedef list<string>::iterator ListIterator ; using ListIterator = list<string>::iterator; is equivalent to:

The friend DeclarationThe friend declaration allows a function external to a class to access the private members of that class.The friend declaration gives the functions and classes it specifies access to the private and protected members of the class in which the friend declaration appears.This effectively makes the named function or class a member of the declaring class.The class itself must declare who its friends are.Friendship is not inherited and is not transitive - if a base class is a friend of a particular class, its derived classes are not automatically friends too.Inheritance (9)47

The friend Declaration#include <iostream>using namespace std;class Box{private: double width;public: friend void printWidth(Box box); void setWidth(double wid ) { width = wid ; } }; void printWidth (Box box) { cout << "Width of box = " << box.width << endl; } // Main function for the program int main() { Box box ; box.setWidth (10.0); printWidth(box); return 0;}Inheritance (9) 48 printWidth () is not a member function of any class, but is a friend of Box class. As a friend of box, printWidth can directly access any member of box.

#include < iostream>#include <string>using namespace std;class MyClass{private: string name;public: MyClass(const string name) { this->name = name; } ~MyClass() = default; friend std::ostream& operator<< (ostream& os, const MyClass& me) { os << "MyClass(" << me.name << ")"; return os; } }; int main(int argc , char* argv []) { MyClass me("Suzy Student"); cout << me << endl; return 0;} FriendsInheritance (9) 49 Returns a reference to the output stream that has been modified. The friend insertion operator function has access to MyClass’ private data members. Defines an independent insertion operator function that is a friend of MyClass. Each member function has an implicit parameter named this whose value is a pointer to the object with which the member function was called.

Follow up… Inheritance (9)50class MyClass{private: string name;public: MyClass(const string n) : name(n) {} ~MyClass() = default; friend std::ostream& operator<< (ostream& lhs, const MyClass& rhs) { lhs << " MyClass(" << name << ")"; return lhs; } }; class MyClass { private: string name; public: MyClass (const string n) : name(n) {} ~ MyClass() = default; string toString() const { ostringstream out; out << "MyClass (" << name << ")"; return out.str(); } friend std::ostream& operator<< (ostream& lhs , const MyClass& rhs ) { lhs << rhs.toString(); return lhs; }}; Using the public toString member function makes more sense. A friend function of a class has the same access privileges to private and protected data as the class member functions.