参考
- 范磊C++(第12课时)
笔记
继承和派生的基本概念
- 什么是继承和派生
- 复杂的继承和派生
- 继承和派生如何在C++中实现?
派生类型(派生权限)的概念,以后会讲到。
单一继承
只有一个基类
#include <iostream>
using namespace std;
class Father
{
private:
int fatherHight,fatherWeight;
public://构造函数只有一个参数,与下面的对应!
void setFatherHight(int x){fatherHight=x;}
void setFatherWeight(int x){fatherWeight=x;}
void getFatherHightAndWeight(){cout<<"身高为"<<fatherHight<<endl;
cout<<"体重为"<<fatherWeight<<endl;}
};
class Son :public Father
{
private:
int sonWidth,sonLong;
public:
void setSonHWidth(int x){sonWidth=x;}
void setSonWLong(int x){sonLong=x;}
void getsonHightAndWeight(){cout<<"肩宽为"<<sonWidth<<endl;
cout<<"臂长为"<<sonLong<<endl;}
};
int main(int argc, const char * argv[]) {
Son LiMing;
LiMing.setFatherHight(180);
LiMing.setFatherWeight(80);
LiMing.setSonWLong(134);
LiMing.setSonHWidth(65);
LiMing.getsonHightAndWeight();
LiMing.getFatherHightAndWeight();
return 0;
}
输出结果:
保护成员
#include <iostream>
using namespace std;
class Father
{
//private://子类不能访问
protected://只能子类来访问
int fatherHight,fatherWeight;
public://构造函数只有一个参数,与下面的对应!
void setFatherHight(int x){fatherHight=x;}
void setFatherWeight(int x){fatherWeight=x;}
//void getFatherHightAndWeight(){cout<<"身高为"<<fatherHight<<endl;
// cout<<"体重为"<<fatherWeight<<endl;}
};
class Son :public Father
{
private:
int sonWidth,sonLong;
public:
void setSonHWidth(int x){sonWidth=x;}
void setSonWLong(int x){sonLong=x;}
//void getsonHightAndWeight(){cout<<"肩宽为"<<sonWidth<<endl;
// cout<<"臂长为"<<sonLong<<endl;}
void PrintAll(){
cout<<"肩宽为"<<sonWidth<<endl;
cout<<"臂长为"<<sonLong<<endl;
cout<<"身高为"<<fatherHight<<endl;
cout<<"体重为"<<fatherWeight<<endl;
}
};
int main(int argc, const char * argv[]) {
Son LiMing;
LiMing.setFatherHight(180);
LiMing.setFatherWeight(80);
LiMing.setSonWLong(134);
LiMing.setSonHWidth(65);
//LiMing.getsonHightAndWeight();
//LiMing.getFatherHightAndWeight();
LiMing.PrintAll();
return 0;
}
输出结果:
共有派生
-
共有
-
保护
-
私有
继承的赋值
子类可以赋值给父类,但父类不能给子类。
因为父类的成员数少。
同样,基类的指针可以指向派生类对象,但是派生类指针不能指向基类对象。
私有派生(继承)
#include <iostream>
using namespace std;
class Father
{
public:
void room(){cout<<"父亲的大房子我可以享受"<<endl;}
};//注意分号
class Son: private Father
{
public:
void enjoy(){room();}
};
int main(int argc, const char * argv[]) {
Son a;
a.enjoy();
return 0;
}
输出结果:
多重继承
#include <iostream>
using namespace std;
class Father
{
public:
void setA(int a ){tall=a;}
void print1(){cout<<"身高的值:"<<tall<<endl;}
private:
int tall;
};
class Mother
{
public:
void setB(int a ){weight=a;}
void print2(){cout<<"体重的值:"<<weight<<endl;}//成员函数名字最好不要相同,否则会报错!
private:
int weight;
};
class Son: public Father,public Mother
{
public:
void setC(int a ){age=a;}
void print3(){print1();print2();cout<<"年龄的值:"<<age<<endl;}
private:
int age;
};
int main(int argc, const char * argv[]) {
Son Mike;
Mike.setA(175);
Mike.setB(80);
Mike.setC(25);
Mike.print3();
return 0;
}
输出:
当然同样的也可以设置派生权限。
继承的构造与构析
构造函数和析构函数的执行顺序。
基类的构造顺序是按继承时的给定顺序执行。
析构时则正好相反。
向基类构造函数传递参数
- 方法1
方法正确,但是调用父类的构造函数对创建子类对象没有帮助,( 无用的构造函数)这相当于浪费了系统的开销。
#include <iostream>
#include<string>
using namespace std;
class Father
{
public:
Father(){cout<<"构造基类对象"<<endl;}
~Father(){cout<<"析构基类对象"<<endl;}
void setA(int a ){tall=a;}
void print(){cout<<name<<"身高的值:"<<tall<<"cm"<<endl;}
protected:
string name;
int tall;
private:
};
class Son :public Father
{
public:
Son(string a, int i, int j){
name=a;
tall=i;
weight=j;
cout<<"构造子类对象"<<endl;}
~Son(){cout<<"析构子类对象"<<endl;}
void setA(int a ){tall=a;}
void print1(){print();cout<<"体重的值:"<<weight<<"kg"<<endl;}//不能覆盖掉父类的,因此要改名。
protected:
int weight;
private:
};
int main(int argc, const char * argv[]) {
Son Mike("Mike",180,80);
Mike.print1();
cout<<"程序结束"<<endl;
return 0;
}
输出:
- 方法2
充分利用基类的构造函数。
#include <iostream>
#include<string>
using namespace std;
class Father
{
public:
//Father(){cout<<"构造基类对象"<<endl;}
Father(string a, int i){
name=a;
tall=i;
cout<<"构造带两个参数的基类对象"<<endl;}
~Father(){cout<<"析构基类对象"<<endl;}
void setA(int a ){tall=a;}
void print(){cout<<name<<"身高的值:"<<tall<<"cm"<<endl;}
protected:
string name;
int tall;
private:
};
class Son :public Father
{
public:
Son(string a, int i, int j):Father(a,i){
weight=j;
cout<<"构造子类对象"<<endl;}
~Son(){cout<<"析构子类对象"<<endl;}
void setA(int a ){tall=a;}
void print1(){print();cout<<"体重的值:"<<weight<<"kg"<<endl;}//不能覆盖掉父类的,因此要改名。
protected:
int weight;
private:
};
int main(int argc, const char * argv[]) {
Son Mike("Mike",180,80);//
Mike.print1();
cout<<"程序结束"<<endl;
return 0;
}
输出:
多重继承容易产生两义性
成员重名导致的问题。
会产生警告⚠️
强行运行的话,就会产生覆盖问题。
可以使用作用域操作符来避免这个问题。
两义性的归属问题
继承中的重载
一旦子类定义了构造函数,基类中的构造函数就会被覆盖。
【问题】const函数,只能由const对象调用吗???