C++继承
继承:字面意思,遗传学这种关系,子类没有新的行为产生
- 父类
- 子类
派生:派生类有新的行为产生
- 基类
- 派生类
继承的难点:
-
继承的实质:父类的属性
-
继承方式:其实就是权限限定词,public,private,protected
-
继承中构造函数写法:必须要用初始化参数列表调用父类构造函数初始化继承下来的数据
-
继承中的权限问题
继承写法:
// 被继承的类--->随便怎么写
#include<iostream>
using namespace std;
class 父类名
{
public:
void print() {
cout << "ILoveyou" << endl;
}
};
// 子类写法
class 子类名 : public 父类名 // : 继承方式 父类名
{
public:
private:
};
// 继承方式:就是权限限定词
// public: 公有继承
// protected: 保护继承
// private: 私有继承
继承实质和权限的理解
- 继承方式只会增强父类的属性在子类当中的权限呈现
- 父类当中私有属性,能被继承,但不能直接访问(不可访问)
- 权限呈现
继承方式 | 父类public | 父类protected | 父类private |
---|---|---|---|
public继承 | public | protected | 不可直接访问 |
protected继承 | protected | protected | 不可直接访问 |
private继承 | private | private | 不可直接访问 |
私有继承:断子绝孙特性
继承的属性一直都在,无论被继承多少次,所以一个类一般不会被继承太深,一般设计代码的时候,三层之内
A被B继承 B被C继承 C被D继承 D被E继承,E类会包含ABCD四个类所有属性和行为
单继承
父类或基类只有一个,称之为单继承
#include<iostream>
using namespace std;
class MM {
public:
MM() { cout << "便于子类构造无参对象" << endl; } // 便于子类构造无参对象
MM(string name , int age):name(name),age(age){}
protected:
string name;
int age;
};
class Boy : public MM {
public:
// 继承中构造函数写法: 必须要用初始化参数列表调用父类的构造函数初始化继承下来的数据
Boy() { // 子类中想要这种,父类必须存在无参构造函数
cout << "构造子类" << endl;
}
// 构造子类对象,必定先调用父类构造函数
// Boy(string name, int age) // 调用父类的无参构造函数
// {
// this->name = name;
// this->age = age;
// }
Boy(string name, int age) : MM(name, age)// 调用父类的带参构造函数
{
}
void printBoy() {
cout << name << "\t" << age << endl;
}
protected:
};
class A {
public:
A(int a) :a(a) {
cout << a;
}
protected:
int a;
};
class B : public A {
public:
B(int a, int b) :A(a) {
this->b = b; // 这个数据也可以用初始化参数列表
cout << b;
}
protected:
int b;
};
// 子类的构造函数只和父类的构造函数有关系,和祖父类没关系
class C : public B
{
public:
C(int a, int b, int c) :c(c), B(a, b)
{
cout << c;
}
protected:
int c;
};
int main() {
Boy boy("boy", 19);
boy.printBoy();
{
// 构造和析构问题
// 先构造父类
C c(1, 2, 3);
// 析构顺序和构造顺序相反;
}
return 0;
}
多继承
多个父类或者基类称之为多继承,多继承注意点和单继承一样,经常会考的是构造和析构顺序问题
#include<iostream>
#include<string>
using namespace std;
class YXC {
public:
YXC(string YXC_Name) :YXC_Name(YXC_Name){}
protected:
string YXC_Name;
};
class XC {
public:
XC(string XCname) :XCname(XCname){}
protected:
string XCname;
};
class XXC : public YXC, public XC {
public:
XXC() :YXC("YXCname"),XC("XCname"){}
XXC(string YXC_Name,string XCname) :YXC(YXC_Name),XC(XCname){}
void printData() {
cout << YXC_Name << "\t" << XCname << endl;
}
protected:
};
class A {
public:
A(int a) :a(a) { cout << a; }
protected:
int a;
};
class B {
public:
B(int b) :b(b) { cout << b; }
protected:
int b;
};
class C {
public:
C(int c) :c(c) { cout << c; }
protected:
int c;
};
// 多继承的构造顺序只和继承顺序有关
class D :public A, public C, public B {
public:
// 构造顺序永远和构造函数的初始化参数列表无关
D(int a, int b, int c, int d) :A(a), B(b), C(c), d(d) {
cout << d;
}
protected:
int d;
};
int main() {
// 多继承写法
XXC xxc;
xxc.printData();
XXC xxc2("YXC", "XC");
xxc2.printData();
// 构造和析构顺序问题
{
D d(1, 2, 3, 4);
}
return 0;
}
虚继承
#include<iostream>
#include<string>
using namespace std;
// 菱形继承和虚继承
class Parent {
public:
Parent(int a) :a(a){}
protected:
int a;
};
class MM :virtual public Parent {
public:
MM(int a,int b) :Parent(a),b(b){}
void printMM() {
cout << a << endl;
}
protected:
int b;
};
class GG : virtual public Parent
{
public:
GG(int a,int c) :Parent(a),c(c){}
void printGG() {
cout << a << endl;
}
private:
int c;
};
class Boy :public MM, public GG
{
public:
Boy() :MM(1, 88), GG(2, 99), Parent(3) {
}
void printData() {
// 只保留一份
cout << a << endl;
cout << MM::a << endl;
cout << GG::a << endl;
printMM();
printGG();
}
private:
};
int main() {
Boy boy;
boy.printData();
return 0;
}
继承中的同名问题
#include<iostream>
#include<string>
using namespace std;
class MM {
public:
MM(string name,int age) :name(name),age(age){}
void print() {
cout << name << "\t" << age << endl;
cout << "MM::print" << endl;
}
void printData() {
cout << "子类没有的父类函数" << endl;
}
protected:
string name;
int age;
};
class Boy : public MM {
public:
Boy() :MM("MM",19){}
void print() {
// 不做特别限定,都是就近原则
cout << name << "\t" << age << endl;
// 类名限定访问属性
cout << MM::name << "\t" << MM::age << endl;
cout << "Boy::print" << endl;
}
protected:
string name = "默认";
string age = "0";
// int num = 1;
};
int main()
{
Boy boy;
boy.print(); 不做特别限定,都是就近原则
// 指针的正常赋值
Boy* pBoy = new Boy;
pBoy->print();
boy.MM::print(); // 类名限定
pBoy->MM::print();
// 指针的非正常赋值
// 父类指针被子类对象初始化
// 1.没有virtual情况看类型
// 2.有virtual 看对象
MM* pMM = new Boy;
pMM->print();
// 子类指针通常是不被运行用父类指针初始化
MM mm("mm", 19);
Boy* pB = (Boy*)&mm; // 霸王硬上
pB->printData();
return 0;
}