继承的概念及入门案例
在C++中,继承是一种面向对象编程的重要概念,他允许一个类(成为派生类)继承另一个类(成为基类)的特性和行为
class B:继承方式A{
};
其中A成为父类(基类、超类) B类成为子类(派生类)
继承方式:
公有继承(public inheritance) 私有继承(private inheritance) 保护继(protected inheritance)
继承的特点
通过继承,派生类可以获得基类的成员变量和成员函数,并且可以添加新成员变量和成员函数。这样可以实现代码的复用
案例
#include<iostream>
#include<string>
using namespace std;
class Animal {
public:
//属性
string name;
int age;
//行为
void eat() {
cout << "在吃饭" << endl;
}
void sleep() {
cout << "在睡觉" << endl;
}
};
class Dog :public Animal {
public:
//属性
string color;
//行为
void lookhome() {
cout << name << "在看家" << endl;
}
void eat() {
cout << name << "在吃骨头" << endl;
}//继承的扩展
void sleep() {
cout << name << "在狗窝里睡觉" << endl;
}//继承的扩展
};//子类
class Cat :public Animal {
public:
string breed;
void catchMouse() {
cout << name << "在抓老鼠" << endl;
}
void eat() {
cout << name << "在吃老鼠" << endl;
}//继承的扩展
void sleep() {
cout << name << "在猫爬架上睡觉" << endl;
}//继承的扩展
};
int main() {
//创建Dog对象
Dog dog;
dog.name = "旺财";
dog.age = 1;
dog.color = "黄色";
dog.eat();
dog.sleep();
dog.lookhome();
//创建Cat对象
Cat cat;
cat.name = "大福";
cat.age = 5;
cat.breed = "银渐层";
cat.eat();
cat.sleep();
cat.catchMouse();
return 0;
}
继承的好处
1.代码复用:
避免了重复编写相同的代码,提高了代码的复用性;
2.扩展性
可以在已有类的基础上进行扩展和修改,添加新的功能或修改现有功能,使代码更具灵活性和可扩展性。
继承使用场景
当多个类之间有相同的属性和方法时,可以将这些共同部分抽取出来放在一个基类中,然后其他类通过继承基类来复用这些代码。
继承方式
什么是权限修饰符?
用来限制类中的成员(成员变量、成员方法....)能够被访问的范围。
修饰符 | 本类里 | 子孙类 | 外部类 |
public | √ | √ | √ |
protected | √ | √ | |
private | √ |
继承方式--公有继承(全部)
#include<iostream>
#include<string>
using namespace std;
class Father {
public:
int a;
protected:
int b;
private:
int c;
public:
void fun1() {
cout << "父类的公共方法" << endl;
}
protected:
void fun2() {
cout << "父类的保护方法" << endl;
}
private:
void fun3() {
cout << "父类的私人方法" << endl;
}
};
//公共继承
class Son1 :public Father {
public:
void fun() {
a = 10;//public
b = 20;//protected
//c = 30;//报错,父类私有,子类不能继承
fun1();//public
fun2();//protected
//fun3();//报错,父类私有,子类不能继承
}
};
int main() {
Son1 s1;
//父类中的a是public,子类可以使用,其他类也可以使用
s1.a = 10;
//父类中的a是protected,子类不可以使用,其他类不可以使用
//s1.b = 20;
//父类中的a是private,子类不可以使用,其他类不可以使用
//s1.c = 30;
s1.fun();
return 0;
}
继承方式--保护继承(本类和子类)
class Son2:protected Father{
public:
void fun() {
a = 10;
b = 20;
//c = 30;报错,父类私有子类不能访问
fun1();//protected权限降级
fun2();//protected
//fun3();报错,父类私有子类不能访问
}
}
其中a在子类中降级为protected
继承方式--私有继承(本类和子类)
class Son3:private Father{
public:
void fun() {
a = 10;//private,权限降级
b = 20;//private,权限降级
c = 30;报错,父类私有子类不能访问
fun1();//private,权限降级
fun2();//private,权限降级
fun3();报错,父类私有子类不能访问
}
}
注意:在类中的有私有变量时,返回值大小为12,反之为8。
通过返回值的字节大小,可以判断出父类中私有成员也是被子类继承,只是由编译器给隐藏后访问不到。
继承中的变量与函数
继承中的构造和析构顺序:
父类构造函数-子类构造函数-子类析构函数-父类析构函数
继承同名成员处理方式
访问子类同名成员 直接访问即可
访问父类 同名成员 需要加作用域
class Base{
public:
int m_A;
public:
Base(){
m_A=100;
}
void fun(){
cout<<"Base--fun()调用"<<endl;
}
void fun(int a){
cout<<"Base--fun(int a)调用"<<endl;
}
};
class Son:public Base{
public:
int m_A;
public:
Son(){
m_A=200;
}
void fun(){
cout<<"Son--fun()调用"<<endl;
}
void fun(int a){
cout<<"Son--fun(int a)调用"<<endl;
}
};
int main(){
//创建对象
Son son;
//访问子类成员:直接访问
cout<<son.m_A<<endl;
son.fun();
son.fun(10);
//访问父类成员:添加父类作用域
cout<<son.Base::m_A<<endl;
son..Base::fun();
son..Base::fun(10);
}
总结:
1.子类对象可以直接访问到子类中同名成员
2.子类对象加作用域可以访问到父类同名成员
继承同名静态成员处理方式
访问子类同名成员 直接访问即可
访问父类 同名成员 需要加作用域
多继承与菱形继承
多继承语法
C++允许一个类继承多个类
#include<iostream>
#include<string>
using namespace std;
class Base1 {
public:
int m_A;
Base1() {
m_A = 100;
}
};
class Base2 {
public:
int m_B = 200;
Base2() {
m_B = 200;
}
};
class Son :public Base1, public Base2 {//多继承
public:
int m_C;
int m_D;
public:
Son() {
m_C = 300;
m_D = 400;
}
};
//访问
int main() {
Son son;
cout << "sizeof Son:" << sizeof(son) << endl;
//多继承容易产生成员同名的情况
//通过使用类名作用域可以区分调用哪一个基类成员
cout << son.Base1::m_A << endl;//100
cout << son.Base2::m_A << endl;//200
cout << son.m_B << endl;//200
cout << son.m_C << endl;//300
cout << son.m_D << endl;//400
}
注意:多继承中如果父类中出现了同名情况,子类使用时要加作用域。
菱形继承(钻石继承)
概念:
1.两个派生类继承同一个基类
2.又有某个类同时继承着两个派生类
#include<iostream>
#include<string>
using namespace std;
class Animal {
public:
int m_Age;
};
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Anmial成为虚基类
class Sheep :virtual public Animal {};
class Tuo : virtual public Animal {};
class SheepTuo :public Sheep, public Tuo {};
int main() {
SheepTuo st;
//st.m_Age = 18;//报错不明确
//使用作用域
st.Sheep::m_Age = 28;
st.Tuo::m_Age = 28;
cout << "st.Sheep::m_Age=" << st.Sheep::m_Age << endl;
cout << "st.Tuo::m_Age=" << st.Tuo::m_Age << endl;
cout << "st.m_Age= " << st.m_Age << endl;
}
//
//输出:
// st.Sheep::m_Age =28
// st.Tuo::m_Age =28
// st.m_Age =28
总结:
菱形继承带来的主要问题是子类继承两份相同数据,导致资源浪费及毫无意义
利用虚继承可以菱形继承问题
综合案例
要求:1.编写图形类Shape,有方法draw()画出图形、函数area()计算面积
2.编写具体图形类:圆Circle,正方形Square,均继承自父类Shape分别实现自己的draw()和area(),输出有意义的描述信息。
#include<iostream>
#include<string>
using namespace std;
class Shape{
public:
void draw() {
cout << "Shape drawing ..." << endl;
}
double area(int i) {
return 0;
}
};
class Circle:public Shape {
private:
double radium;
double const PI = 3.14;
public:
Circle(double r) {
radium = r;
}
void draw() {
cout << "Circle drawing..." << endl;
}
double area() {
return PI * radium * radium;
}
};
class Square :public Shape {
private:
double side;
public:
Square(double side) {
this->side = side;
}
void draw() {
cout << "Square drawing..." << endl;
}
double area() {
return side * side;
}
};
int main() {
Shape s;
s.draw();
cout << "Shape's area:" << s.area()<< endl;
Circle c(10.0);//有参构造函数
c.draw();
cout << "Circle'area:" << c.area() << endl;
Square sq(20.0);//有参构造函数
sq.draw();
cout << "Square's area:" << sq.area() << endl;
return 0;
}