面向对象编程之继承
定义一个类的时候想重用一个已有的类,就可以使用继承。
class NewClass:public OldClass{
//新增加的成员
};
新类会继承旧类的全部成员,成为新类中的成员。新类可以增加新的成员,实现对旧类的扩展。继承方式可以有public/private/protected三种,一般使用public方式。旧类成为“父类”或者“基类”,新类称为“子类”或者“派生类”。无论哪种继承方式都是把父类的成员全部继承到子类中成为子类的成员,其中私有的成员在子类中不能直接访问,公开成员可以在子类中直接访问。特权是,父类中可以用protected来作为成员的访问限制,这种成员称为保护成员。这种成员对外跟private一样,但在子类中允许直接访问。×××尽量不用protected以免父子类之间有太强的耦合×××
不同继承方式的区别在于继承到子类中之后作为子类的成员对外的访问限制
private方式继承过来后所有的成员都成为子类的私有成员
protected方式继承过来之后原来的私有还是私有,原来保护的和公开的都成为子类的保护成员
public继承过来的成员到子类中之后保持原有的访问限制不变
如果没写继承方式默认是private
继承的主要作用是代码重用以及对多态提供支持。
#include<iostream> using namespace std; #include<string> class Person{ protected://允许在子类中直接访问,不允许在别的地方访问 string name; public: void setname(const char* n){ name=n; } void eat(string food){ cout<<name<<"吃"<<food<<endl; } void speak(string words){ cout<<name<<"说:|"<<words<<"|"<<endl; } }; class Teacher:public Person{ string course; public: void teach(string someclass){ cout<<this->name <<"给"<<someclass<<"讲"<<course<<"课"<<endl; } void setcourse(string c){course=c;} }; int main() { Person a; a.setname ("芙蓉"); a.eat("水煮鱼"); a.speak("我会跳舞"); Teacher c; c.setname ("短哥"); c.eat("杂酱面"); c.speak("大家好!"); c.setcourse ("C++"); c.teach ("csd"); system("pause"); }
创建对象的顺序:分配内存,构造函数首先调用父类的构造函数,然后按照定义顺序创建成员对象,执行构造函数的函数体。析构跟构造相反。构造函数默认调用父类构造函数是不传参数,如果需要传递参数,要在初始化类表中用父类雷鸣来表示。×××初始化列表各项排名不分先后,只是指明用什么初始化谁×××
子类定义的函数会隐藏来自父类的同名函数,即使参数表不同也不会构成重载。如果确实需要调用来自父类的那个函数,需要明确用“类名::”来指明。父子类之间不存在重载。
#include<iostream> using namespace std; #include<string> class Person{ string name; public: const string& getName(){return name;} Person(const char* n):name(n){ cout<<"Person("<<n<<")"<<endl; } ~Person(){ cout<<"~Person"<<endl; } void show(){ cout<<"大家好,我是"<<name<<endl; } }; class Teacher: public Person{ string course; public: Teacher(const char* n,const char* c):course(c),Person(n){ //Person(n);只是创建匿名对象,这个语句后立即释放 cout<<"Teacher("<<n<<","<<c<<")"<<endl; } ~Teacher(){ cout<<"~Teacher()"<<endl; } void show(const char* c){//隐藏来自父类的同名函数 cout<<c<<"班的同学们好!我是"<<course<<"课程老师:"<<getName()<<"!"<<endl; } }; int main() { Person b("芙蓉"); b.show(); Teacher a("苍老师","C++"); a.Person::show();//调用父类的show函数 a.show("1");//调用子类的show函数 system("pause"); }
多重继承,一个类可以继承多个类,把所有父类的成员都全部继承过来,可以为每个父类制定一种继承方式。
多个父亲的构造函数按继承顺序调用,与初始化列表中的顺序无关。析构顺序相反。
#include<iostream> #include<string> using namespace std; class Phone{ public: Phone(){cout<<"Phone()"<<endl;} void Call(string Num){ cout<<"打电话给:"<<Num<<endl; } }; class Camera{ public: Camera(){cout<<"Camera()"<<endl;} void takephoto(string target){ cout<<"照了一张"<<target<<"照。"<<endl; } }; class CellPhone:public Phone,public Camera{ public: //按照继承顺序调用父类构造函数 CellPhone(){cout<<"CellPhone()"<<endl;} }; int main() { CellPhone Nokia; Nokia.Call("芙蓉"); Nokia.takephoto("风景"); system("pause"); }
虚继承
如果希望某一个类被继承到某一级子类中时有了多份要合并只保留一份,这个类在被继承的时应该用virtual声明为虚继承,这个类就称为虚基类。
虚继承(钻石继承)中虚基类的构造函数由最底下(合并)的子类的构造函数直接传递参数
虚基类
/ \
子类1 子类2
\ /
子类
#include<iostream> using namespace std; #include <string> class Person{ string name; public: Person(const char* n):name(n){ cout<<"Person("<<n<<")"<<endl; } const string& Name()const{return name;} }; class Teacher : virtual public Person{//virtual虚继承 string course; public: Teacher(const char* n,const char* c):course(c),Person(n){ cout<<"Teacher("<<n<<","<<c<<")"<<endl; } void Teach(const char* c){ cout<< Name()<<"老师在"<<c<<"班讲课"<<endl; } }; class Student :virtual public Person{//virtual虚继承 string sid; public: Student(const char* n,const char* s):sid(s),Person(n){ cout<<"Student("<<n<<","<<s<<")"<<endl; } void listen(const char* room){ cout<<Name()<<"在"<<room<<"听课"<<endl; } }; class DoubleMan : public Student,public Teacher{ public: DoubleMan(const char* n, const char* c,const char* id):Teacher(n,c),Student(n,id),Person(n){ //Person(n)虚基类的构造函数在这里直接传递 cout<<"DoubleMan("<<n<<","<<c<<","<<id<<","<<")"<<endl; } }; int main() { DoubleMan dm("短哥","C++","X1110"); dm.Teach("csd"); dm.listen("508"); cout<<"hello,"<<dm.Name()<<endl; system("pause"); return 0; }