类与类之间的关系 继承
1 继承说明
1 子类拥有父类的所有变量和成员函数
2 子类可以拥有父类没有的方法和属性
#include<iostream>
using namespace std;
class Parent {
public:
void print() {
cout << "a:" << a << endl;
cout << "b:" << b << endl;
}
int a;
int b;
};
//class Children :private Parent
//class Children :protected Parent
class Children :public Parent {
private:
int c;
};
void main() {
Children c1;
c1.a = 2;
c1.b = 3;
c1.print();
}
2 子类的访问控制
1 单个类的访问控制
C++继承方式对子类访问影响
- public继承, 父类成员在子类中保持原有访问级别
- private继承, 父类成员在子类中变为private成员
- protected继承, 父类public成员在子类变为protected;父类protected成员在子类仍为protected;父类private成员在子类仍为private; protected 关键字修饰的成员变量和成员函数是为了继承
private成员在子类中依然存在,但是无法访问,不论哪种继承,子类都无法使用父类的私有成员
共有继承
// public 修饰成员变量和方法 类内部和外部都能使用
// private 修饰成员变量和方法 类内部使用,继承子类中可用
// private 修饰成员变量和方法 类内部使用 外部不能用
class Parent {
public:
int a;
protected:
int b;
private:
int c;
public:
void printT() {
cout << "printT" << endl;
}
};
class Children :public Parent {
public:
void useVar() {
a = 0;
b = 0;
//c = 0; 不能访问
}
};
void main() {
Parent t1, t2, t3;
t1.a = 10;
// t1.b = 20; // 不能访问
// t1.c = 30; // 不能访问
}
私有继承
class Parent {
public:
int a;
protected:
int b;
private:
int c;
public:
void printT() {
cout << "printT" << endl;
}
};
class Children2 :private Parent {
public:
void useVar() {
a = 0;
b = 0;
// c = 0; 不能访问
}
};
void main() {
Children2 c2;
/*c2.a = 10; 不能访问
c2.b = 20;
c2.c = 30;*/
}
保护继承
class Parent {
public:
int a;
protected:
int b;
private:
int c;
public:
void printT() {
cout << "printT" << endl;
}
};
class Children3 :protected Parent {
public:
void useVar() {
a = 0;
b = 0;
// c = 0; //不能访问
}
};
void main() {
Children3 c3;
/*c3.a = 10;
c3.b = 20;
c3.c = 30;*/
}
判断时看调用语句在类的内部还是类的外部;再看子类是怎么从父类继承的;再看父类的访问级别。
类的访问属性控制
class A {
private:
int a;
protected:
int b;
public:
int c;
A() {
a = 0; b = 0; c = 0;
}
void set(int a, int b, int c) {
this->a = a; this->b = b; this->c = c;
}
};
class B :public A {
public:
void print() {
//cout << "a=" << a;
cout << "b=" << b;
cout << "c=" << c << endl;
}
};
class C :protected A {
public:
void print() {
//cout << "a=" << a;
cout << "b=" << b;
cout << "c=" << c << endl;
}
};
class D :private A {
public:
void print() {
//cout << "a=" << a;
cout << "b=" << b;
cout << "c=" << c << endl;
}
};
void main() {
A aa;
B bb;
C cc;
D dd;
aa.c = 100;
bb.c = 100;
// cc.c = 100; // 保护
// dd.c = 100; // 私有
aa.set(1, 2, 3);
bb.set(10, 20, 30);
// cc.set(40, 50, 60); // 保护
// dd.set(70, 80, 90); //
bb.print();
cc.print();
// dd.print();
}
3 继承中的构造和析构
1 类型兼容性原则
- 子类对象当作父类对象使用
- 子类对象可以直接赋值给父类对象
- 子类对象可以初始化父类对象
- 父类指针可以直接指向子类对象
- 父类引用可以直接引用子类对象
#include<iostream>
using namespace std;
class Parent {
public:
Parent() {
cout << "构造函数" << endl;
}
Parent(const Parent& obj) {
cout << "拷贝构造函数" << endl;
}
void printP() {
cout << "parent" << endl;
}
private:
int a;
};
class Child :public Parent {
public:
void printC() {
cout << "child" << endl;
}
private:
int c;
};
void howToPrint(Parent* base) {
base->printP(); // 父类成员函数
}
void howToPrint2(Parent &base) {
base.printP(); // 父类成员函数
}
void main() {
Parent p1;
p1.printP();
Child c1;
c1.printC();
c1.printP();
// 类型兼容性原则
// 1-1 基类指针(引用)指向子类对象
Parent* p = NULL;
p = &c1;
p->printP();
// 1-2 指针做函数参数
howToPrint(&p1);
howToPrint(&c1);
// 1-3 引用做函数参数
howToPrint2(p1);
howToPrint2(c1);
// 2
// 让子类对象初始化父类对象
// 子类就是一种特殊的父类
Parent p3 = c1;
}
2 继承中对象模型
- 子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化
- 子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理
3 先父类构造再子类构造,先子类析构再父类析构
// 先调用父类构造函数,再调用子类构造函数
// 析构顺序与构造相反
class Parent {
public:
Parent(int a, int b) {
this->a = a;
this->b = b;
cout << "parent构造函数" << endl;
}
/*Parent(const Parent& obj) {
cout << "拷贝构造函数" << endl;
}*/
~Parent() {
cout << "Parent析构函数" << endl;
}
void printP() {
cout << "parent" << endl;
}
private:
int a;
int b;
};
class Child :public Parent {
public:
Child(int a, int b, int c):Parent(a,b) {
this->c = c;
cout << "child构造函数" << endl;
}
~Child() {
cout << "Child析构" << endl;
}
void printC() {
cout << "child" << endl;
}
private:
int c;
};
void howToPrint(Parent* base) {
base->printP(); // 父类成员函数
}
void howToPrint2(Parent &base) {
base.printP(); // 父类成员函数
}
void objplay() {
Child c1(1, 2, 3);
}
void main() {
//Parent p(1, 2);
objplay();
}
结果
parent构造函数
child构造函数
Child析构
Parent析构函数
4 继承和组合混搭
// 继承和组合混搭?
class Object {
public:
Object(int a, int b) {
this->a = a;
this->b = b;
cout << "Object构造函数" << " a " << a << " b " << b << endl;
}
~Object() {
cout << "Object析构函数" << " a " << a << " b " << b << endl;
}
protected:
int a;
int b;
};
class Parent:public Object {
public:
Parent(char *p) :Object(1,2){
this->p = p;
cout << "Parent构造函数" << p << endl;
}
~Parent() {
cout << "Parent析构函数" << p << endl;
}
void printP() {
cout << "parent" << endl;
}
protected:
char* p;
};
class Child :public Parent {
public:
Child(char *p) :Parent(p),obj1(3,4),obj2(5,6) {
this->myp = p;
cout << "child构造函数" << myp << endl;
}
~Child() {
cout << "Child析构" << myp << endl;
}
void printC() {
cout << "child" << endl;
}
private:
char* myp;
Object obj1;
Object obj2;
};
void objplay() {
Child c1((char*)"继承测试");
}
void main() {
objplay();
}
结果
Object构造函数 a 1 b 2
Parent构造函数继承测试
Object构造函数 a 3 b 4
Object构造函数 a 5 b 6
child构造函数继承测试
Child析构继承测试
Object析构函数 a 5 b 6
Object析构函数 a 3 b 4
Parent析构函数继承测试
Object析构函数 a 1 b 2
5 继承中的同名成员变量处理方法
class A {
public:
int a;
int b;
public:
void get() {
cout << "b: " << b << endl;
}
void print() {
cout << "A" << endl;
}
};
class B:public A {
public:
int b;
int c;
public:
void get_child() {
cout << "b: " << b << endl;
}
void print() {
cout << "B" << endl;
}
};
// 同名成员变量,同名成员函数
void main() {
B b1;
b1.b = 1;
b1.get_child();
b1.A::b = 100; // 修改父类
b1.B::b = 200; // 修改子类 默认情况
b1.get();
b1.print();
b1.A::print();
b1.B::print(); // 默认情况
}
结果
b: 1
b: 100
B
A
B
6 static
// 继承中static
class A {
public:
static int a;
int b;
A() {
cout << "A构造函数" << endl;
}
public:
void get() {
cout << "b: " << b << endl;
}
void print() {
cout << "A" << endl;
}
};
int A::a = 100; // 不仅变量赋值,更重要告诉编译器分配内存,继承类中使用a,不然报错
class B :private A {
public:
int b;
int c;
public:
void get_child() {
cout << "b: " << b << endl;
cout << "a: " << a << endl;
}
void print() {
cout << "B" << endl;
}
};
// 1 static遵守派生类访问控制规则
// 2 int A::a = 100;不仅变量赋值,更重要告诉编译器分配内存,继承类中使用a,不然报错
// 3 A类中添加构造函数
void main() {
A a1;
a1.print();
B b1;
b1.get_child();
// b1.a = 200;
}
多继承
1 一个类有多个直接基类继承关系(B继承Base1,Base2)
// 多继承
class Base1 {
public:
Base1(int b1) {
this->b1 = b1;
}
void printB1() {
cout << "b1:" << b1 << endl;
}
private:
int b1;
};
class Base2 {
public:
Base2(int b2) {
this->b2 = b2;
}
void printB2() {
cout << "b2:" << b2 << endl;
}
private:
int b2;
};
class B :public Base1, public Base2 {
public:
B(int b1, int b2, int c) :Base1(b1),Base2(b2){
this->c = c;
}
void printC() {
cout << "c:" << c << endl;
}
private:
int c;
};
void main() {
B b(1, 2, 3);
b.printB1();
b.printB2();
b.printC();
}
2 虚继承
// 虚继承
class B {
public:
int b;
};
class B1:virtual public B {
public:
int b1;
};
class B2:virtual public B{
public:
int b2;
};
class C:public B1, public B2 {
public:
int c;
};
void main() {
C c1;
c1.b1 = 100;
c1.b2 = 200;
c1.c = 300;
c1.b = 500; // b不明确,加virtual可以解决
}
不调用B中的b时,去掉virtual,调用两次B的构造函数
class B {
public:
int b;
B() {
cout << "B构造函数" << endl;
}
};
class B1 : public B {
public:
int b1;
};
class B2 : public B {
public:
int b2;
};
class C:public B1, public B2 {
public:
int c;
};
void main() {
C c1;
}
一个类有两个父类,且父类成员中有相同的名字
class D1 {
public:
int k;
};
class D2 {
public:
int k;
};
class E :public D1, public D2 {
};
void main() {
E e1;
e1.D1::k = 10;
e1.D2::k = 20;
}
virtual关键字会给类变量增加属性
class B {
public:
int b;
B() {
cout << "B构造函数" << endl;
}
};
class B1:virtual public B {
public:
int b1;
};
class B2 : public B {
public:
int b2;
};
class C:public B1, public B2 {
public:
int c;
};
void main() {
cout << sizeof(B) << endl; //4
cout << sizeof(B1) << endl; //12 virtual关键字会给变量增加属性
cout << sizeof(B2) << endl; //8
}