当前位置:网站首页>Chapter 13 Class Inheritance-1

Chapter 13 Class Inheritance-1

2022-08-11 05:45:00 Zinxso

13.1 一个简单的基类

从一个类派生出另一个类时,The original class is called 基类,The inherited class is called派生类.
Assume primitive classesTableTenniesPlayer:

class TableTenniesPlayer
{
    
   private:
       string firstName;
       string lastName;
       bool hasTable;
   public:
       TableTennisPlayer(const string &fn = "none", const string &ln = "none", bool ht = false);
       void Name() const;
       bool HasTable() const{
    return hasTable};
       void ResetTable(bool v) {
    hasTable = v;};
}

in the original classTableTennisClass类新增一个属性,It includes the member's score in the game,语法格式:

class RatePlayer:public TableTennisPlayer
{
    
    private:
       unsigned int rating;
   public:
       RatedPlayer(unsigned int r = 0, const string &fn = "none", const string &ln = "none", bool ht = false);
       RatePlayer(unsigned int r, const TableTennisPlayer &tp);
       unsigned int Rating() const {
     return rating;};
       void ResetRating(unsigned int r) {
    rating = r;};
};

上述代码中,冒号指出RatePlayerWhen the base class of the classTableTenniePlayer,“public”表示TableTennisPlayer是一个公有基类,称为公有派生.
使用公有派生,基类的公有成员将成为派生类的公有成员;基类的私有部分也将成为派生类的一部分,但只能通过基类的公有和保护方法访问.RatedPlayer具有以下特征:
1、派生类对象存储了基类的数据成员(继承了基类的实现);
2、派生类对象可以使用基类的方法(继承了基类的接口).
Derived classes need to add the following to the inheritance feature:
1、自己的构造函数,And the constructor must give the new member(如果有)和继承的成员提供数据;
2、Additional data members and member functions can be added as needed.
上述RatePlayerEach member of the first constructor corresponds to a formal parameter;The second constructor uses oneTableTennisPlayer参数.

13.1.2 构造函数:访问权限

派生类不能直接访问基类的私有成员,Only accessible through base class methods;RatePlayer构造函数不能直接设置继承的成员,You must use the public methods of the base class to access private base class members.
派生类构造函数必须使用基类构造函数.创建派生类对象时,The base class object should be created first.That is, the base class object should be created before the program enters the derived class constructor.(This is similar to the previous chapterconst A member initialization list for members),

 RatedPlayer::RatedPlayer(unsigned int r = 0, const string &fn = "none", const string &ln = "none", bool ht = false):TableTennisPlayer(fn, ln, ht)
 {
    
     rating = r;
  }

" :TableTennisPlayer(fn, ln, ht) “即为成员初始化列表.
But here if” :TableTennisPlayer(fn, ln, ht) “注释掉” //:TableTennisPlayer(fn, ln, ht) "程序将使用默认的基类构造函数.(This situation is not guaranteed to be correct,可根据实际情况,Choose to call the correct constructor by default or explicitly

13.3 多态公有继承

The same method behaves differently in derived and base classes,Its exact behavior depends on the object on which the method is called——多态.
以下2mechanism can be achieved多态公有继承
● 在派生类中Redefine the base class的方法
● 使用虚方法虚函数
举例,Brass Account.
Brass Account信息:

  • 客户姓名;
  • 账号;
  • 当前结余.
    可执行操作:
  • 创建账户;
  • 存款;
  • 取款;
  • 显示账户信息
    Brass PlusAdd an item of information:
  • 透支上限;
  • 透支贷款利率;
  • 当前的透支总额.
    No new operations are added,修改以下2个操作:
  • 对于取款操作,Consider overdraft protection;
  • Display operation is required 显示Brass Plus账户的其他信息.
    brass.h
#ifndef __BRASS_H_
#define __BRASS_H_

#include<iostream>
#include<string>
using namspace std;

class Brass
{
    
    privat:
           string fullName;
           long acctNum;
           double balance;
    public:
           Brass(const string &s = "NullBody", long an = -1, double bal = 0.0);
           void Deposit(double amt);
           virtual void WithDraw(double amt);
           double Balance() const;
           virtual void ViewAcct() const;
           virtual ~Brass() {
    };
}

class BrassPlus:public Brass
{
    
     private:
             double maxLoan;
             double rate;
             double owesBank;
     public:
             Brass(const string &s = "NullBody", long an = -1, double bal = 0.0, dobule ml = 0.0, double rate = 0.11255);//When the function is defined, use the initialization list to implement or write a constructor as follows
             Brass(Brass &ba, dobule ml = 0.0, double rate = 0.11255);
             virtual void WithDraw(double amt);
             virtual void ViewAcct() const;
             void ResetMax(double m) {
    max Loan = m;}
             void ResetRate(double r) {
    rate = r;}
             voied ResetOwes() {
    owesBank = 0;}
             virtual ~Brass() {
    };
             
}
#endif

程序说明:

  1. For methods that behave the same in both classes, declare them only in the base class.
  2. 关键字virtual.Used to determine which method to use when a method is called by reference or pointer(基类ormethods in derived classes)如果没有使用virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,The method is then chosen based on the type of object pointed to by the reference or pointer.
    对于Brass对象dom,BrassPlus对象dot:
//
Brass &b1 = dom;
Brass &b2 = dot;

//非virtual
b1.ViewAcct();      //调用Brass::ViewAcct()
b2.ViewAcct();      //调用Brass::ViewAcct()

//virtual
b1.ViewAcct();      //The reference points to the base class,调用Brass::ViewAcct()
b2.ViewAcct();      //Application points to the derived class,调用BrassPlus::ViewAcct()

注意:如果要在派生类中Redefine the base class的方法,Base class methods should be declared as virtual.Methods are declared in the base class as virtualThe virtual method will then be automatically generated in the derived class,It is recommended to add clarity.
1、类实现
Brass.cpp/Brass method
在这里插入图片描述
Brass.cpp/BrassPlus method

Brass::BrassPlus(const string &s, long an, double bal, double ml, double r):Brass(s, an, bal)
{
    
       maxLoan = ml;
       owesBank = 0.0;
       rate = r;
}

BrassPlus::BrassPlus(const Brass &a, double ml, double r):Brass(ba)
{
    
       maxLoan = ml;
       owesBank = 0.0;
       rate = r;
}

void Brass::ViewAcct() const
{
    
       Brass::ViesAcct();
       cout << "Maxium load : $" << maxLoan << endl;
       cout << "Load rate : $" << rate << endl;
       cout << "Owed to bank : $" << owesBank << endl;
}

void BrassPlus::WithDraw(double amt)
{
    
       double bal = Balance();
       if(amt <= bal)
               BrassWithDraw(amt);
       else if(amt <= bal + maxLoan - owesBank)
       {
    
               double advance = amt - bal;
               owesBank = advance *(1.0 + rate);
               cout << "Bank Advance : $" << advance << endl;
               cout << "Finance charge : $" << advance * rate << endl;
               Deposit(advance);
               Brass::WithDraw(amt);
       }
       else
                cout << "Credit limit exceeded." << endl;
               
}

2、类使用

#include <iostream>
#include "brass.h"

using namespace std;

int main(void)
{
    
    Brass Rick("Rick", 123456, 4000.00);
    BrassPlus Jack("Jack", 654123, 3000.00);
    Rick.ViewAcct();
    Jack.ViewAcct();
    Jake.Deposit(100.00);
    Rick.WithDraw(502.00);
    return 0;
}

Calling the above code through the object of the class will only call the method of the base class,There is no feature of using virtual methods.
Virtual methods can only be called by reference or pointer.
3、虚方法的使用
Virtual methods are used with pointers or references

#include <iostream>
#include "brass.h"

using namespace std;
connst int CLIENTS = 3; 
int main(void)
{
    
    //An array of base class pointers for the class
    Brass *pClients[CLIENTS];
    for(int i = 0; i< CLIENTS; i++)
    {
    
         cout << "Enter the name: ";
         getline(cin, temp); //字符串
         cout << "Enter account number:";
         cin >> tempNum;
         cout << "Enter account balence:";
         cin >> tempBal;
         cout << "Enter 1 for Brass or 2 for BrassPlus: ";
         while(cin >> kind && (kind != 1 && kind != 2))
               cout << "Enter either 1 or 2: ";
         if(kind == 1)
               p_Clients[i] = new Brass(temp, tempNum, tempBal);    //newThe constructor is called to create the object
         else
         {
    
               double tmax, trate;
               cout << "Enter the overDraft limit: ";
               cin >> tmax;
               cout << "Enter the rate: ";
               cin >> trate;
               pClient[i] = new BrassPlus(temp, tempNum, tempBal, tmax, trate);

         }
         //At the end of a cycle, you need to kill the carriage return to enter the next cycle
         while(cin.get() != '\n');   
    }
    cout << endl;
    
    for(int i = 0; i< CLIENTS; i++)
    {
    
         pClients[i]->ViewAcct();   //Which one to choose depends on the type of object pointed to by the pointerViewAcct()
         cout << endl;
    }
    for(int i = 0; i< CLIENTS; i++)
    {
    
         delete pClients[i];   //new后需要delete
         cout << endl;
    }
    return 0;
}

A base class pointer can point to a base class object or a derived class object,反之不可(Derived classes can only point to derived classes).
4、为何需要虚析构函数
3in the code shown indelete释放由newThe allocated object code states that the accumulation should contain a virtual destructor.如果析构函数不是虚的,则将只调用对应于指针类型的析构函数.The above code is onlyBrassThe destructor is called even if the pointer points to BrassPlus对象;反之,The destructor of the corresponding object type is called.
则应在Brass.hAdd a virtual destructor to the base class as follows

virtual ~Brass() {
    };

13.4 静态联编和动态联编

function binding(binding):Function calls in source code are interpreted as executing a specific block of function code.
静态联编:Binding during compilation is static binding,Also known as early linking.
Virtual functions make it impossible to determine which function to use at compile time(It depends on the type of invocation at runtime).
动态联编:The generation of code by the compiler that selects the correct virtual function at program runtime is called dynamic binding,Also known as late linking.

13.4.2 虚成员函数和动态联编

1、Default static binding
The reason static binding still exists:效率和概念模型.
效率:The class will not be used when the base class,no derived class,不需要动态联编;有派生类,But the derived class does not redefine any methods of the base class,No dynamic binding is required.
2、虚函数的工作原理
Objects of every class have a hidden member——一个指针,指向一个数组,Each member of the array is a pointer to a function.该数组称为虚函数表.
Using virtual functions has a cost in terms of memory and execution speed.

13.4.3 虚函数注意事项

  • Keywords are used in base class method declarationsvirtual可使该方法在基类以及所有派生类中是虚的;
  • 如果使用指向对象的引用或指针来调用虚方法,程序将使用对象类型定义的方法,Not a method defined by a reference or pointer type(13.3The usage code of the virtual method).这称为动态联编.
  • 如果定义的类将被用作基类,The class method to be redefined in the derived class should be declared virtual.
    Supplements related to virtual methods:
    1、构造函数:构造函数不能为虚函数.
    2、析构函数:Should be a virtual function,除非类不用做基类.Runtime after definition,The destructor of the derived class will be called first to free the memory(Derived classes add components),Then call the destructor of the base class to free the memory(Base class component).
    注意A virtual destructor should normally be provided to the base class,Even if it's not needed.
    3、友元:不能是虚函数,Friends are not member functions,Only members can be virtual functions.
    4、没有重新定义:If the derived class does not redefine the function it will use the function in the base class;If the derived class is in the derivation chain the latest virtual function version will be used(Except that the cumulative version is hidden)
    5、重新定义将隐藏方法:There are two rules to follow:
  • 如果重新定义继承的方法,应确保与原来的原型完全相同,But if the return type is a base class reference or pointer,can be modified to a reference or pointer to a derived class.
  • 如果基类声明被重载了,则应在派生类中重新定义所有的基类版本.If only redefine one version,Additional versions will be hidden.
原网站

版权声明
本文为[Zinxso]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/223/202208110512453933.html