SEU C++下半部分总结第八章、第九章、第十章(二)

继承

继承是面向对象程序设计的核心思想之一。通过继承,我们可以大大提升代码的可复用性。
在面向对象程序设计中,类是对象的抽象,比如说我们设计一个Person类,这个类有姓名,年龄几个属性,用Person这个类去生成对象,就有了你,我,不同的人。你、我就是具体的人(对象)。
了解了面向对象的程序设计思想,就能更好地理解继承的概念。如果我们还需要一个Student类,Student有姓名,年龄,成绩几个属性。我们发现Student类与Person类都有年龄,姓名的属性。我们都知道Student一定是一个Person,继承就是用来表达这种“是”的关系。

class Person{
private:
    string name;
    int age;
public:

    Person(string n,int a): name(n),age(a){};

    Person(const Person &person){
        name = person.name;
        age = person.age;
    }

    ~Person(){};

    const string &getName() const {
        return name;
    }

    void setName(const string &name) {
        Person::name = name;
    }

    int getAge() const {
        return age;
    }

    void setAge(int age) {
        Person::age = age;
    }

};

class Student:public  Person{
private:
    double grade;
public:
    Student(const string &n, int a, double grade) : Person(n, a), grade(grade) {}
    Student( const Student &student) : Person(student.getName(),student.getAge()) {
        grade = student.grade;
    }

    double getGrade() const {
        return grade;
    }

    void setGrade(double grade) {
        Student::grade = grade;
    }
};
  • 定义继承的语法是:
    class 类名 : 继承方式 基类名1,基类名2…
    这里的继承方式只需要掌握public就可以。
  • 当派生类生成对象时需要先调用基类的构造函数,在对象消亡时,会先调用派生类的析构函数。
  • 派生类可以直接访问基类中的protected成员
  • C++允许多重继承,即一个类可以继承自多个类

复写

我们给Person类加上一个say方法

void say(){
        cout<<"I am a Person"<<endl;
    }

那么此时如果在Student类中调用say方法,那么也会打印“I am a Person”,如果我们希望Student类能有自己独特的行为,我们就需要重载say方法,可以在Student类中加上以下代码

void say(){
        cout<<"I am a Student"<<endl;
    }

在用Student类的对象调用say方法时,编译器就会自动选择我们加入的特殊方法。

复写方法时,返回值类型,函数名,参数列表必须完全相同。

函数重载

如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数。
mian函数不能重载 编译器根据调用语句当中的实参个数和类型判断应该调用哪个函数(不能通过返回值类型进行区分)

向下转型

为了更好地说明,我们再引入一个Worker类

class Worker : public Person{
private:
    double salary;
public:
    Worker(const string &n, int a, double salary) : Person(n, a), salary(salary) {}

    double getSalary() const {
        return salary;
    }

    void setSalary(double salary) {
        Worker::salary = salary;
    }

    void say()
    {
        cout<<"I am a worker"<<endl;
    }
};

当我们要办理身份证时,不需要考虑这个Person是Student还是Worker,只需要使用它们作为Person的特性。
这时我们就可以用到向下转型,通俗的说就是可以用基类指针来操作派生类对象,也就是可以直接把Student和Worker的对象直接当做Person对象来用。

    Person *person;
    Student student("Bob",18,56.4);
    person  = &student;
    person->getName();
    Worker worker("Jerry",40,2000);
    person = &worker;
    person->getName();

多态

还是以上述代码为例,当我们把派生类对象当做基类对象使用时,在调用其say方法时,调用的是基类的方法还是派生类中的方法呢?

Person *person;
    Student student("Bob",18,56.4);
    person = &student;
    cout<<person->getName()<<endl;
    person->say();
    
结果为:
Bob
I am a Person

显然,调用了基类的say方法,如果我们希望它还能调用派生类的say方法呢?
这就要用到虚函数,虚函数是C++多态的核心。我们只需要在基类的方法前添加上关键字virtual即可。

virtual void say(){
        cout<<"I am a Person"<<endl;
    }

再次执行上述代码,我们发现结果变成了
Bob
I am a Student

虚函数实现原理

当我们在函数定义前加上virtual关键字时,系统会自动为这个类的每一个对象建立一张虚函数表,用基类指针访问对象时,会先在虚函数表中找到对应的函数。(原理较复杂,了解即可)

多态的使用

在C++中,只有通过指针或者引用调用函数,该函数才会参与多态。

Person person[2];
    Student student("Bob",18,56.4);
    Worker worker("Jerry",40,2000);
    person[0]  = student;
    person[1] = worker;
    person[0].say();
    person[1].say();
  
 结果:
 I am a Person
I am a Person

纯虚函数和抽象基类

如果我们再改变一下Person类中的say函数

 virtual void say() = 0;

这时的say函数就是一个纯虚函数,纯虚函数不能在类中给出函数的具体实现(可以在派生类或类外给出实现)。
只要类中有一个函数是纯虚的,那么这个类就不能直接生成对象,代码Person person(“Kally”,10);就会报错。
但是依然可以生成对应的指针,代码 Person *person;
依然可以执行,所以抽象基类依然可以参与多态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值