参考书籍:

C++ Primer
Essential C++

编译器:

gcc / g++

C++继承

继承的实质就是父类有的属性在子类中也存在一份。只是根据继承方式不同,在子类中权限的体现不同。

继承:子类没有新的属性或者行为产生

  • 父类
  • 子类

派生:派生类中有新的属性产生

  • 基类
  • 派生类

单继承

只有父类的继承称之为单继承

写法

class 父类 {

};
class 子类:继承方式 父类名 {

};
//继承方式就是权限限定词
//公有继承: public
//保护继承: protected
//私有继承: private

继承中权限问题


public

protected

private

public继承

public

protected

不可访问

protected继承

protected

protected

不可访问

private继承

private

private

不可访问

综上: 权限限定词只会增强权限(public:最低权限 private:最高权限)

#include <iostream>
#include <string>
using namespace std;
//父类
class MM {
public:
string getName() {
return name;
}
void print() {
cout << name << "\t" << age << endl;
}

protected:
int age = 18;

private:
string name = "默认";
};
//子类
//公有继承
class Boy : public MM {
public:
// print()
void printBoy() {
// cout << name << endl; 不可能访问
cout << age << endl;
print();
}

protected:
// int age

private:
// string name; 不能访问
};
//保护继承
class Girl : protected MM {
public:
void printGirl() {
cout << age << endl;
print();
}

protected:
// void print()
// int age;
private:
// string name;
};
//私有继承
class Son : private MM {
public:
void printSon() {
print();
cout << age << endl;
// cout << name << endl;
// //父类的私有属性子类不能使用 只能间接调用父类的非私有方法访问
cout << getName() << endl;
}

protected:
private:
// void print();
// int age;
// string name;
};
int main(int argc, char** argv) {
Boy boy;
boy.print();
boy.printBoy();

Girl girl;
// girl.print(); //无法访问
girl.printGirl();

Son son;
son.printSon();

return 0;
}

注意点:

  • 继承的属性无论被继承多少次,都存在, A 被B继承 B被C继承 C被D继承 D包含ABC中所有属性
  • 继承不易过多继承,导致子类臃肿
  • 私有继承可以阻断父类属性被孙子类去使用(断子绝孙)

继承中构造函数写法

  • 写法:子类必须先构造父类对象(子类必须调用父类的构造函数) ,调用父类的构造函数必须采用初始化参数列表
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A() {
cout << a;
}
A(string a) : a(a) {
cout << a;
}
~A() {
cout << a;
}

protected:
string a = "A";
};
class B : public A {
public:
B() { //就算没写,也会调用父类的无参构造函数
cout << b;
}
//子类完整写法: 除了初始化自身数据,还需要初始化父类数据
B(string a, string b) : A(a) {
this->b = b; //自身属性可以采用初始化列表
cout << b;
}
void print() {
cout << a;
cout << b;
}
~B() {
cout << b;
}

protected:
string b = "B";
};
class C : public B {
public:
C(string a, string b, string c) : B(a, b), c(c) {
cout << c;
}
void print() {
cout << a << b << c << endl;
}
~C() {
cout << c;
}

protected:
string c;
};
int main(int argc, char** argv) {
{
B b;
cout << endl;
B object("A", "B");
cout << endl;
object.print();
cout << endl;
C c("A", "B", "C");
cout << endl;
c.print();
}
cout << endl;
{
cout << "构造和析构顺序问题:" << endl;
C cobject("A", "B", "C");
// ABCCBA
}
return 0;
}

多继承

多继承就是存在两个以及两个以上父类

  • 权限问题和构造函数和单继承一样的
#include <iostream>
#include <string>
using namespace std;
class Father {
public:
Father(string FFName) : FFName(FFName) {}

protected:
string FFName;
};
class Monther {
public:
Monther(string MFName) : MFName(MFName) {}

protected:
string MFName;
};
class Son : public Father, public Monther {
public:
Son(string FFName, string MFName, string SSName)
: Father(FFName), Monther(MFName) {
this->SFName = FFName + MFName;
this->SSName = SSName;
}
void print() {
cout << FFName << endl;
cout << MFName << endl;
cout << this->SFName + this->SSName << endl;
}

protected:
string SFName;
string SSName;
};
int main(int argc, char** argv) {
Son son("李", "田", "大牛");
son.print();
return 0;
}

菱形继承

菱形继承是因为多继承存在问题而衍生的继承方式(菱形继承就是虚继承)

#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(int a) : a(a) {}
int a = 666;
};
class B : virtual public A {
public:
B(int a) : A(a) {}
};
class C : virtual public A {
public:
C(int a) : A(a) {}
};
//多继承构造顺序只和这个地方顺序(继承顺序)有关
class D : public C, public B {
public:
//子类必须调用爷爷构造函数
D(int a) : C(14), B(12), A(a) {}
void print() {
cout << A::a << endl;
cout << B::a << endl;
cout << C::a << endl;
}
};
int main(int argc, char** argv) {
D dobject(23);
dobject.print();

return 0;
}

继承中同名问题

  • 数据成员同名
  • 成员函数同名
#include <iostream>
#include <string>
using namespace std;
class MM {
public:
MM(string name) : name(name) {}
void print() {
cout << "-------------------------" << endl;
cout << "MM::name" << endl;
cout << "-------------------------" << endl;
}

protected:
string name;
};
class Son : public MM {
public:
Son() : name("Son"), MM("MM") {}
void print() {
cout << "-------------------------" << endl;
cout << "Son::name" << endl;
// No.1 不写任何标识 ,就近原则
cout << name << endl;
// No.2 可以用类名
cout << MM::name << endl;
cout << "-------------------------" << endl;
}

protected:
string name;
};

void printInfo(MM* p) {
p->print();
}
int main(int argc, char** argv) {
//对象访问:
// No.1 不写任何标识 ,就近原则
Son son;
son.print();
son.MM::print();
son.Son::print();
MM mm("MM");
mm.print();
//指针访问
//正常初始化访问
cout << "正常初始化指针访问" << endl;
Son* pSon = new Son;
pSon->print();
MM* pMM = new MM("MM");
pMM->print();
//非正常初始化访问
// 1.1 父类指针用子类对象初始化
//在没有写任何修饰词的,看指针类型
MM* pFather = new Son;
pFather->print(); //调用那个函数?
// 1.2 子类指针被父类对象初始化,危险,一般不这样做
// Son* pp = new MM("MM"); //错误的
Son* pp = NULL;
pp = static_cast<Son*>(&mm); //强制类型转换类似C语言强制
// pp->print(); //程序中断,没办法执行
cout << "当父类指针成为函数参数时候,传参子类和父类对象通用" << endl;
printInfo(pMM);
printInfo(pSon);
return 0;
}