C + + Object Oriented Programming

C + + object oriented programming (5)

1. Concepts of inheritance and derivation

Inheritance: when defining a new class B, if the class is similar to an existing class A (B has all the characteristics of a), you can take a as a base class and B as a derived class (also known as a subclass) of the base class.

Derived classes are obtained by modifying and extending the base class. In derived classes, new member variables and member functions can be extended.

Once defined, a derived class can be used independently of the base class.

Derived classes have far from member functions and member variables of the base class, whether public, protected or private.

In each member function of a derived class, private members in a base class cannot be accessed.

Writing method:

Class derived class name: public base class name {};

class CStudent{
  private:
  string sName;
  int nAge;
  public:
  bool isThreeGood(){};
  void SetName(const string &name){sName=name;}
};
class CUndergraduateStudent:public CStudent{
  private:
  int nDepartment;
  public:
  bool is ThreeGood(){};//cover
  bool CanBaoYan(){};
};
class CGraduatedStudent:public CStudnet{
  private:
  int nDepartment;
  char szMentorName[20];
  public:
  int CountSalary(){};
};
  • Memory space of derived class objects

The volume of the derived class object is equal to the volume of the base class object plus the volume of the derived class object's own member variables. The derived class object contains the base class object, and the storage location of the base class object is before the new member variable of the derived class object.

#include <iostream>
#include <string>
using namespace std;
class CStudnet{
  private:
  string name;
  string id;
  char gender;
  int age;
  public:
  void PrintInfo();
  void SetInfo(const string & name_,const string &id_,int age_,char gender_);
  string GetName(){return name;}
};
class CUndergraduateStudent:public CStudnet{
  private:
  string department;
  public:
  void QUalifiedForBaoYan(){
    cout<<"qualified for baoyan"<<endl;
  }
  void PrintInfo(){
    CStudnet::PrintInfo();
    cout<<"Department:"<<department<<endl;
  }
  void SetInfo(const string &name_,const string &id_,int age_,char gender_,const string&department_){
    CStudnet::SetInfo(name_,id_,age_,geender);
    department=department_;
  }
};
void CStudent::PrintfInfo(){
  cout<<"Name:"<<name<<endl;
  cout<<"ID:"<<id<<endl;
  cout<<"Age:"<<age<<endl;
  cout<<"Gender:"<<gender<<endl;
}
void CStudnet::SetInfo(const string&name_,const string & id,int age_,char gender_){
  name=name_;
  id=id_;
  age=age_;
  gender=gender_;
}
int main(){
  CUndergraduateStudnet s2;
  s2.SetInfo("Harry Potter","118829212",19,'M',"Computer Science");
  cout<<s2.GetName()<<" ";
  s2.QualifiedForBaoYan();
  s2.printInfo();
  return 0;
}

Exercise:

If a variety of things have some common characteristics and different characteristics, how to write classes to represent these things is more appropriate? (C)

A) Write a class for each thing independently, and the classes are independent of each other

B) Write a class to represent one of the things, and the classes representing other things are derived from this class

C) Summarize the common characteristics of all things and write a base class. Then write a class for everything, all derived from the base class

D) Write a class that contains all the characteristics of all things, and then use a member variable as a marker to distinguish different kinds of things

2. Inheritance relationship and compound relationship

Inheritance: Yes relationship:

  • Base classes a and B are derived from base class A
  • Logically, "A B object is also an A object"

Compliance: "yes" relationship

  • There is a member variable k in class C. If k is the object of class D, then C and D are compound relationships
  • General logical requirements: C object is the inherent attribute or component of C object

Give me a chestnut 🌰

  1. Is it appropriate to derive CWoman from CMan?

    This is certainly unreasonable, because "a woman is also a man" is logically untenable.

    A better approach is to summarize the common characteristics of men and women, write a Chuman class to represent "people", and then CMan and CWoman both derive from Chuman.

  2. Circle class derived from point class?

    Considering "whether a circle is a point" is not logical, so we use composite relationship instead of inheritance relationship. (the compliance relationship is more reasonable)

    Each circle object contains a "point" object, which is the center of the circle.

Exercise:

Which of the following derivation relationships is reasonable

A) Flying insects are derived from insects

B) Derive the circle class from the point class

C) Dogs are derived from wolves

D) Mammals derived from reptiles

  • Use synthesis of composite relationships

If you want to write a community dog management program, you need to write a "owner" class and a "dog" class.

The dog has a owner, and the owner is the owner (assuming that a dog has only one owner, but a owner can have up to 10 dogs)

  1. Let's first analyze whether the following is reasonable
class CDog;
class CMaster{
  CDog dogs[10];
};
class CDog{
  CMaster m;//Such a definition is a circular definition and is wrong
};
//Detailed explanation:
//One cmaster accounts for the volume of 10 cdogs, one CDog accounts for the volume of 1 Cmager, and another cmaster accounts for the volume of 10 cdogs. Therefore, the specific volume cannot be calculated, and an error will be reported during compilation
  1. Let's see if the following is reasonable
//Set a member object of the owner class for the dog class
//Set a dog object pointer array for the owner class
class CDog;
class CMaster{
  CDog *dogs[10];
};
class CDog{
  CMaster m;//If you modify the owner's information of a dog, the owner's information of other dogs should also be modified. It's not good
};
  1. Let's see if the design is reasonable
//Design an object pointer of owner class for dogs
//Design an array of dog objects for the owner class
class CMaster;//CMaster must be declared in advance. You cannot write CMaster class before CDog class.
class CDog{
  CMaster *pm;
};
class CMaster{
  CDog dogs[10];
};
//The objects of the dog are included in the owner. The operation of the dog must pass through the owner. The dog loses its freedom, so it is still not a good practice
  1. Right approach
//Design an object pointer of owner class for dogs
//Design a dog object pointer array for the owner class
class CMaster;//CMaster must be declared in advance. You cannot write CMaster class before CDog class
class CDog{
  CMaster m;
};
class CMaster{
  CDog *dogs[10];
};

3. Coverage and protection of members

  • Derived classes override base class members

A derived class can define a member with the same name as a base class member, which is called override. When accessing such members in a derived class, the default is to access the members defined in the derived class. To access the members with the same name defined by the base class in the derived class, use the scope symbol::.

Note: Generally speaking, base classes and derived classes do not define member variables with the same name, but it is common to define member functions with the same name. The following chestnut is convenient to understand, but it is not recommended to write so

class base {
  int j;
  public:
  int il;    
  void func();
};
class derived:public base{
  public:
  int i;
  void access();
  void func();
};
void derived::access(){
  j=5;//Error, inaccessible
  i=5;//i of derived class
  base::i=5;//i of base class
  func();//func of derived class
  base::func();//func of base class
}

Exercise:

The derived class and the base class have member functions with the same name and the same parameter table. This phenomenon: (D)

A) Duplicate definitions are not allowed

B) Overloading of functions

C) It is called override. In derived classes, the function with the same name of the base class is useless

D) It is called override, which reflects the modification of the characteristics inherited from the base class by the derived class

The following statement is correct: (B)

A) A derived class can have a member function with the same name as the base class, but cannot have a member variable with the same name (error, OK)

B) In the member function of a derived class, you can call the member function of the base class with the same name and the same parameter table (correct)

C) The member function with the same name of the derived class and the base class must have different parameter tables, otherwise it is defined repeatedly (error)

D) The member variables of the derived class and the base class with the same name are stored in the same storage space (error)

  • Protected member of class

private, public and protected access rights

  • private member of base class:
    1. Member function of base class
    2. Friend function of base class
  • public member of base class:
    1. Member function of base class
    2. Friend function of base class
    3. Member functions of derived classes
    4. Friend function of derived class
    5. Other functions
  • protected member of base class
    1. Member function of base class
    2. Friend function of base class
    3. The member function of the derived class can access the protected member of the base class of the current object
class Father{
  private:int nPrivate;
  public:int nPublic;
  protected:int nProtected;
};
class Son:public Father{
  void AccessFather(){
    nPublic=1;//ok
    nPrivate=1;//wrong, private members of the parent class cannot be accessed
    nProtected=1;//ok
    Son f;
    f.nProtected=1;//wrong, f is not the current object, is a protected member, but cannot be accessed
  }
};
int main(){
  Father f;
  Son s;
  f.nPublic=1;//ok
  s.nPublic=1;//ok
  f.nProtected=1;//error, can only be modified through member functions
  f.nPrivate=1;//error
  s.nProtected=1;//error
  s.nPrivate=1;//error,
  return 0;
}

4. Constructor of derived class

class Bug{
  private:
  int nLegs; int nColor;
  public:
  int nType;
  Bug(int legs,int color);
  void PrintBug(){};
};
class FlyBug:public Bug{
  int nWings;
  public:FlyBug(int legs,int color,int wings);
};
Bug::Bug(int legs,int color){
  nLegs=legs;
  nColor=color;
}
FlyBug::FlyBug(int legs,int color,int wings){
  nLegs=legs;//Error, private member of base class cannot be accessed
  nColor=color;//error
  nType=1;//ok
  nWings=wings;
}
FlyBug::FlyBug(int legs,int color,int wings):Bug(legs,color){
  nWings=wings;
}
int main(){
  FlyBug fb(2,3,4);
  fb.PrintBug();
  fb.nType=1;
  fb.nLegs=2;//error nLegs is a private member
  return 0;
}

When creating an object of a derived class, you need to call the constructor of the base class: initialize the members inherited from the base class in the derived class object. Before executing the constructor of a derived class, the constructor of the base class is always executed first.

There are two ways to call the base class constructor:

  • Display method: in the constructor of the derived class, provide parameters for the constructor of the base class

    ​ derived::derived(arg_derived-list):base(arg_base-list)

  • Implicit method: when the base class constructor is omitted in the constructor of the derived class, the constructor of the derived class will automatically call the default constructor of the base class.

When the parsing function of the derived class is executed, the destructor of the base class will be called automatically after the destructor of the derived class is executed.

class Base{
  public:
  int n;
  Base(int i):n(i){
    cout<<"Base"<<n<<" constructed"<<endl;
  }
  ~Base(){
    cout<<"Base"<<n<<" destructed"<<endl;
  }
};
class Derived:public Base{
  public:
  Derived(int i):Base(i){
    cout<<"Derived constructed"<<endl;
  }
  ~Derived(){
    cout<<"Derived destructed"<<endl;
  }
};
int main(){
  Derived Obj(3);
  return 0;
}
//Base 3 constructed
//Derived constructed
//Derived destructed
//Base 3 destructed
  • Constructor notation for derived classes containing member objects
class Bug{
  private:
  int nLegs; int nColor;
  public:
  int nType;
  Bug(int legs,int color);
  void PrintBug(){};
};
class Skill{
  public:
  Skill(int n){};
};
class FlyBug:public Bug{
  int nWings;
  Skill sk1,sk2;
  public:
  FlyBug(int legs,int color,int wings);
};
FlyBug::FlyBug(int legs,int color,int wings):Bug(legs,color),sk1(5),sk2(color),nWings(wings){}

  • Constructor execution order for enclosing derived class objects

When creating an object of a derived class

(1) First execute the constructor of the base class to initialize the members inherited from the base class in the derived class object.

(2) Then execute the destructor of the member object class to initialize the member object in the derived class object.

(3) Finally, execute the derived class's own constructor.

When a derived class object dies:

(1) Execute the derived class's own destructor first

(2) Execute the destructor of each member object class again

(3) Finally, the destructor of the base class is executed

Destructors are called in the reverse order of constructors.

5. Assignment compatibility rules of public inheritance

class base{};
class derived:public base{};
base b;
derived d;

(1) Objects of derived classes can be assigned to base class objects

​ b=d;

(2) Derived class objects can initialize references to base classes

​ base & br=d;

(3) The address of the derived class object can be assigned to the base class pointer

​ base *pb=&d;

If the derivation method is private or protected, the above three items do not work

class base{};
class derived:protected base{};
base b;
derived d;

When protected inherits, the public members and protected members of the base class become protected members of the derived class.

During private inheritance, the public member of the base class becomes the private member of the derived class, and the protected member of the base class becomes the inaccessible member of the derived class.

The inheritance of protected and private is not a "yes" relationship.

  • Pointer cast between base and derived classes
  1. In the case of public derivation, the pointer of the derived class object can be directly assigned to the base class pointer
Base * ptrBase=&objDerived;

ptrBase points to a Derived object

*ptrBase can be regarded as an object of Base class. The public members accessing it can be accessed directly through ptrBase, but the members belonging to Derived class but not Base class in objDerived object cannot be accessed through ptrBase.

  1. Even if the base class pointer points to an object of a derived class, you cannot access the members of the base class without a derived class through the base class pointer.

  2. By forcing pointer type conversion, ptrBase can be converted to a pointer of Derived class

Base *ptrBase=&objDerived;
Derived *ptrDerived=(Derived *)ptrBase;
//Programmers should ensure that ptrBase points to an object of Derived class, otherwise it is easy to make mistakes
#include <iostream>
using namespace std;
class Base{
  protected:
  int n;
  public:
  Base(int i):n(i){
    cout<<"Base"<<n<<" constructed"<<endl;
  }
  ~Base(){
    cout<<"Base"<<n<<" destructed"<<endl;
	}
  void Print(){
    cout<<"Base:n="<<n<<endl;
  }
};
class Derived::public Base{
  public:
  int v;
  Derived(int i):Base(i),v(2*i){
    cout<<"Derived constructed"<<endl;
  }
  ~Derived(){
    cout<<"Derived detructed"<<endl;
  }
  void Func(){};
  void Print(){
    cout<<"Derived:v="<<v<<endl;
    cout<<"Derived:n="<<n<<endl;
  }
};
int main(){
  Base objBase(5);
  Derived objDerived(3);
  Base * pBase=&objBase;
  //pBase->Func(); Base class has no func function
  //pBase->v=5; Error. Base class has no V variables
  pBase->Print();
  //Derived *pDerived=&objBase; Error, it can only be the type of base class, not derived class. The object pointer points to the base class
  Derived *pDerived=(Derived*)(&objBase);
  pDerived->Print();//Brave, unexpected errors may occur, and v is not a member variable of the base class
  pDerived->v=128;//Writing data into someone else's space can cause problems.
  objDerived.Print();
  return 0;
}
  • Direct and indirect base classes

Class A is the direct base class of class B, class B is the direct base class of class C, then class A is the indirect base class of class C.

When declaring a derived class, you only need to list its direct base class

  1. A derived class automatically inherits its indirect base class up the class hierarchy

  2. Members of derived classes include

    A member defined by a derived class itself

    Direct all members in the base class

    All members of all indirect base classes

#include <iostream>
using namespace std;
class Base{
  public:
  int n;
  Base(int i):n(i){
    cout<<"Base"<<n<<"constructed"<<endl;
  }
  ~Base(){
    cout<<"Base"<<n<<"destructed"<<endl;
  }
};
class Derived:public Base{
  public:
  Derived(int i):Base(i){
    cout<<"Derived constructed"<<endl;
  }
  ~Derived(){
    cout<<"Derived destructed"<<endl;
  }
};
class MoreDerived:public Derived{
  public:
  MoreDerived():Derived(4){
    cout<<"More Derived constructed"<<endl;
  }
  ~MoreDerived(){
    cout<<"More Derived Destructed"<<endl;
  }
};
int main(){
  MoreDerived obj;
	return 0;
}

Exercise:

The following statement is correct: (C)

A) When a derived class object is generated, the constructor of the derived class is executed before the constructor of the base class. (later)

B) When a derived class object dies, the destructor of the base class executes before the destructor of the derived class. (later)

C) If the base class has a parameterless constructor, the constructor of the derived class can take no initialization class table.

D) The member variables of the base class can be accessed in the middle of the constructor of the derived class. (public or protected can be accessed, but private members also need to call the constructor of the base class to access indirectly).

Keywords: C++

Added by elpaisa on Fri, 17 Sep 2021 07:04:25 +0300