继承与派生

it2024-10-26  36

继承与派生

类的继承与派生

继承的优点和缺点:

代码共享,减少创建类的工作量,每一个子类都有父类的方法和属性提高代码的重用性,减少代码的冗杂程度提高代码的可拓展性,调用别人的接口,加继承父类实现继承是侵入性的,子类拥有父类的全部属性和方法增强了耦合性,父类常量、变量、方法被修改时,子类可能需要重构

继承代码示例

class Student { public: Student(int id, string name) { this->id = id; this->name = name; } void printS() { cout << "id=" << this->id << " name=" << this->name << endl; } private: int id; string name; }; class Student2 { public: Student2(int id, string name, int score) { this->id = id; this->name = name; this->score = score; } void printS() { cout << "id = " << this->id << ",name=" << this->name << endl; cout << "score= " << this->score << endl; } private: int id; string name; int score; }; //Student3继承于Student,子类继承了父类的成员和公有的函数 class Student3 :public Student { public: Student3(int id, string name, int score) :Student(id, name) { this->score = score; } void printS() { Student::printS(); cout << "score = " << this->score << endl; } private: int score; }; //类Student3通过继承Student实现了类Student2的功能

派生类的组成,基类+新增成员

继承的方式

只要是父类中的private成员,不管什么继承方式,子类都无法继承,但可以通过public来间接访问,比如get(),构造函数什么的如果是public继承,子类的访问控制权限保持不变如果是proteceed继承,子类中除了private成员,其余在子类中都是protected子类可以直接访问父类的public成员子类内部可以访问父类protected成员,但类外不能访问

三条原则:

看调用的成员变量是在类的外部还是在类的内部看当前变量在子类中的访问控制权限看子类的继承方式 publicprotectedprivate公有继承(public)publicprotected不可见保护继承(protected)protectedprotected不可见私有继承(private)privateprivate不可见

代码示例:

class Parent { public: int pub;//类的内部和外部都可以访问 protected: int pro;//类的内部可以访问,类的外部不可以访问 private: int pri;//类的内部可以访问,类的外部不可以访问 }; class Child :public Parent { public: void func() { cout << pub << endl; } }; //保护继承 class Child2 :protected Parent { public: void func2() { pub;//通过protected继承,能够在类的内部访问 //pub在类的内部可以访问,类的外部不可以访问,子类可以访问 //pub就是protected成员 pro;//pro跟pub是一样的性质,都是protected } }; class Sub_child2 :public Child2 { public: void sub_func2() { pub; pro; } }; //继承Child类 class SuChild :public Child { void func2() { } }; class Child3 :private Parent { public: void func3 { pub;//类的内部可以访问,类的外部不能访问 //子类不能访问 pro;//跟pub一样 } }; class Sub_Child3 :public Child3 { public: void sun_fun3() { } };

继承关系具体代码举例

#include<iostream> using namespace std; 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;//a是父类的私有成员,访问不了 cout << "b= " << b;//b在类的内部可以访问 cout << "c= " << c << endl;//类的内部和外部都可以访问 } }; class C :protected A { public: void print() { //cout << "a= " << a;//a是父类的私有成员,访问不了 cout << "b= " << b;//b在类的内部可以访问,类的外部不能访问 cout << "c= " << c << endl;//类的内部和外部都可以访问 } }; class D :private A { public: void print() { //cout << "a= " << a;//a是父类的私有成员,访问不了 cout << "b= " << b;//私有继承b在类的内部可以访问,外部不可以访问 cout << "c= " << c << endl;//类的内部可以访问,外部不可以访问 } }; int 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(1, 2, 3); //cc.set(1, 2, 3);//不能访问 //dd.set(1, 2, 3);//不能访问 bb.print(); cc.print(); dd.print(); return 0; }

类的兼容性原则

子类对象可以当做父类对象使用子类对象可以直接赋值给父类对象子类对象可以直接初始化父类对象父类指针可以直接指向子类对象父类引用可以直接引用子类对象

练习代码:

#include<iostream> using namespace std; class Parent { public: int a; //int c; void printP() { cout << "a" << this->a << endl; } }; class Child :public Parent { public: void printC() { cout << "b=" << this->a; } int b; }; void myPrint(Parent* pp) { pp->printP; } int main(void) { Parent* pp=NULL; Child* cp=NULL; Parent p; Child c; pp = &c;//c的内存布局能够满足父类指针的全部需求 //可以用一个子类的对象地址给父类指针赋值 pp->a; pp->printP(&c); return 0; }

子类的构造与析构

子类构造函数会默认调用父类无参构造在子类构造函数之前会先调用父类的构造函数如果子类要调用父类的有参构造,需要给父类有参构造函数传值析构函数会先调用子类的析构函数然后才调用父类的析构函数

代码示例

#include<iostream> using namespace std; class Parent { public: Parent() { a = 0; cout << "parent()" << endl; } Parent(int a) { this->a = a; cout << "parent(int)" << endl; } ~Parent() { cout << "Parent析构" << endl; } int a; }; class Child :public Parent { public: //在调用子类,默认调用父类构造函数 Child(int a,int b):Parent(a) { cout << "Child(int,int)..." << endl; this->a = a; this->b = b; } void printC() { cout << "b=" << b << endl; } ~Child() { cout << "Child析构" << endl; } int b; }; int main() { Child c(10,20); c.printC(); //c.~Child(); return 0; }

子类与父类的成员重名

父类和子类即使成员变量名相同,但由于内存地址不同,不影响父类成员变量名通过::访问传参过程是先在子类构造函数建临时变量,通过临时变量传参

代码示例:

#include<iostream> using namespace std; class Parent { public: int a; Parent(int a) { this->a = a; } }; class Child :public Parent { public: int a; Child(int p_a,int c_a):Parent(c_a)//Parent(p_a) { this->a = p_a;//this->a = c_a; } void print() { cout << Parent::a << endl; cout << this->a << endl;//子类的A } }; int main() { Child c(10, 100); c.print(); return 0; }

继承中的static

static在类内声明,在类外初始化static归类,所有成员共享static在继承关系中,同样也别被子类共享

多继承与虚继承

关键字virtual,虚继承,在发生多继承的时候,子类重复的只会有一个继承

多继承即一个子类继承了多个父类,仅C++有

class 子类:public 父类,public 父类....

虚继承重复的部分只有一块内存

代码示例:

#include<iostream> using namespace std; //定义家具类 class Furniture { public: int m;//材质 }; //继承父类虚继承,防止子类发生不明确现象 class Bed:virtual public Furniture { public: void sleep() { cout << "go to bed" << endl; } }; class Sofa:virtual public Furniture { public: void sit() { cout << "relax on the sofa" << endl; } }; class SofaBed:public Bed,public Sofa { public: void SleeAndSit() { sleep(); sit(); } }; int main() { Bed b; b.sleep(); Sofa s; s.sit(); cout << "-------------" << endl; SofaBed sb; sb.SleeAndSit(); sb.m = 100;//如果不加vitural不明确只能够通过::访问 system("pause"); return 0; }
最新回复(0)