C++(单继承、派生)


继承

继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程。例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数。

#include<iostream>
using namespace std;

//基类 Pelple
class People{
public:
    void setname(string name);
    void setage(int age);
    string getname();
    int getage();
private:
    string m_name;
    int m_age;
};
void People::setname(string name){m_name = name;}
void People::setage(int age){ m_age = age; }
string  People::getname(){ return m_name; }
int People::getage(){ return m_age;}

//派生类 Student
class Student: public People{
public:
    void setscore(float score);
    float getscore();
private:
    float m_score;
};
void Student::setscore(float score){ m_score = score; }
float Student::getscore(){ return m_score; }

int main(){
    Student stu;
    stu.setname("小明");
    stu.setage(16);
    stu.setscore(95.5f);
    cout<<stu.getname()<<"的年龄是 "<<stu.getage()<<",成绩是 "<<stu.getscore()<<endl;

    return 0;
}

输出结果:
在这里插入图片描述

C++继承时的名字遮蔽问题

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,那么就会遮蔽从基类继承过来的成员。所谓遮蔽,就是在派生类中使用该成员(包括在定义派生类时使用,也包括通过派生类对象访问该成员)时,实际上使用的是派生类新增的成员,而不是从基类继承来的。

#include<iostream>
using namespace std;

//基类People
class People{
public:
    void show();
protected:
    string m_name;
    int m_age;
};
void People::show(){
    cout<<"嗨,大家好,我叫"<<m_name<<",今年"<<m_age<<"岁"<<endl;
}

//派生类Student
class Student: public People{
public:
    Student(string name, int age, float score);
public:
    void show();  //遮蔽基类的show()
private:
    float m_score;
};
Student::Student(string name, int age, float score){
    m_name = name;
    m_age = age;
    m_score = score;
}
void Student::show(){
    cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}

int main(){
    Student stu("小明", 16, 90.5);
    //使用的是派生类新增的成员函数,而不是从基类继承的
    stu.show();
    //使用的是从基类继承来的成员函数
    stu.People::show();

    return 0;
}

输出结果:
在这里插入图片描述

C++基类和派生类的构造函数

基类构造函数不会被继承,不能当做普通的成员函数来调用。换句话说,只能将基类构造函数的调用放在函数头部,不能放在函数体中。

#include<iostream>
using namespace std;

//基类People
class People{
protected:
    string m_name;
    int m_age;
public:
    People(string, int);
};
People::People(string name, int age): m_name(name), m_age(age){}

//派生类Student
class Student: public People{
private:
    float m_score;
public:
    Student(string name, int age, float score);
    void display();
};
//People(name, age)就是调用基类的构造函数
Student::Student(string name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
    cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl;
}

int main(){
    Student stu("小明", 16, 90.5);
    stu.display();

    return 0;
}

输出结果:
在这里插入图片描述

基类构造函数调用规则

通过派生类创建对象时必须要调用基类的构造函数,这是语法规定。换句话说,定义派生类构造函数时最好指明基类构造函数;如果不指明,就调用基类的默认构造函数(不带参数的构造函数);如果没有默认构造函数,那么编译失败。请看下面的例子:

#include <iostream>
using namespace std;

//基类People
class People{
public:
    People();  //基类默认构造函数
    People(string name, int age);
protected:
    string m_name;
    int m_age;
};
People::People(): m_name("xxx"), m_age(0){ }
People::People(string name, int age): m_name(name), m_age(age){}

//派生类Student
class Student: public People{
public:
    Student();
    Student(string, int, float);
public:
    void display();
private:
    float m_score;
};
Student::Student(): m_score(0.0){ }  //派生类默认构造函数
Student::Student(string name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
    cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"。"<<endl;
}

int main(){
    Student stu1;
    stu1.display();

    Student stu2("小明", 16, 90.5);
    stu2.display();

    return 0;
}

输出结果:
在这里插入图片描述
在这里插入图片描述
输出结果:
在这里插入图片描述

C++基类和派生类的析构函数

和构造函数类似,析构函数也不能被继承。与构造函数不同的是,在派生类的析构函数中不用显式地调用基类的析构函数,因为每个类只有一个析构函数,编译器知道如何选择,无需程序员干涉。

另外析构函数的执行顺序和构造函数的执行顺序也刚好相反:

  • 创建派生类对象时,构造函数的执行顺序和继承顺序相同,即先执行基类构造函数,再执行派生类构造函数。
  • 而销毁派生类对象时,析构函数的执行顺序和继承顺序相反,即先执行派生类析构函数,再执行基类析构函数。
#include <iostream>
using namespace std;

class A{
public:
    A(){cout<<"A constructor"<<endl;}
    ~A(){cout<<"A destructor"<<endl;}
};

class B: public A{
public:
    B(){cout<<"B constructor"<<endl;}
    ~B(){cout<<"B destructor"<<endl;}
};

class C: public B{
public:
    C(){cout<<"C constructor"<<endl;}
    ~C(){cout<<"C destructor"<<endl;}
};

int main(){
    C test;
    return 0;
}

输出结果:
在这里插入图片描述

实验题目1:班级学生学期成绩管理系统 (1)程序功能简介 灵活运用类的继承、对象成员等机制,设计一个能够实现班级学生学期成绩管理的程序。 (2)程序设计说明 ① 个人信息类CPerson的数据成员有姓名、性别、年龄、身份证号等数据成员,成员函数根据需要自行设计; ② 学生类CStudent从CPerson派生,并增加学号、CCourse对象成员数组(大小至少3个)等数据成员,并根据需要自行设计成员函数,包括能够求解所选修课程的总学分、显示某个学生基本信息和课程信息的成员函数; ③ 课程类CCourse包括课程名、学分、分数、任课老师等数据成员,成员函数根据需要自行设计; ④ 班级类CClass的数据成员有班级名称、班级人数、CStudent对象成员数组(大小由构造函数确定)等。本班级类CClass的对象成员数组需要在构造函数中用new动态分配内存空间,在析构函数中用delete释放。在CClass类中设计包括能够求解最高成绩、最低成绩和平均成绩以及通过学号查找并输出某个学生全部信息(例如Seek())等功能在内的成员函数; ⑤ 构造三十个学生的数据,每个学生都有三门课程成绩,输出并显示这些数据; ⑥ 根据类的需要添加适当的其它成员,编写完整的程序并测试。 (3)程序调试运行 运行程序查看结果,并进行源代码调试和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃秃秃秃哇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值