继承
继承(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;
}
输出结果: