C++学习:面向对象之继承

来源:互联网 发布:2016淘宝最大的店铺 编辑:程序博客网 时间:2024/06/05 11:58

C++学习:面向对象之继承


简介:
在面向对象思想中有三大重点要素:封装(encapsulation),继承(inheritance),多态(polymorphism),这三个最最重要的思想,因为在面向对象的思想中,万物皆是对象,所有东西都是可以归为一类的,例如在自然界中的分类可以有界门纲目科书种,而封装是抽象的过程.继承和多态是相对于封装更加抽象的一类,比如:我们把一个学生Student看做是一类,但是Student由是人的一部分,人呢又是生物的一部分等等,而Student往下可以是某某中学的的学生,等等,所以这个时候就需要我们学会去抽象的看待他们.猴子继承了灵长类动物,灵长类动物由是动物,动物又是自然届中的生物,等等.一层一层的,当然面向对象的思想不是三言两语就可以说完的.


提示:
本文博主:章飞_906285288
博客地址:http://blog.csdn.net/qq_29924041


继承的特性

继承需要的关系是is-a的关系,父类更通用更抽象,而子类需要更特殊更具体
继承背后的思想就是基于已经存在的类来构建新类
当从已经存在的类继承的时候,就重用了它的方法和成员,还可以添加新的方法和成员来定制新类以应对需求.
从其他类到处的类叫做子类(派生类),被导出的类叫做父类(基类)
继承在OOP中是不可或缺的
继承可以更好的代码重用
继承可以体现不同的继承的体系
根据访问限制符号来分的话:继承可以有public(共有继承),private(私有继承),protected(保护继承)这三种表示形式


公有继承

最简单的共有继承方式://Student类继承Person类class Student : public Person{}

通过代码讲原理:

/* * =========================================================================== * *       Filename:  person.h *    Description:  : *        Version:  1.0 *        Created:  2017年06月18日 12时58分18秒 *       Revision:  none *       Compiler:  gcc *         Author:   (),  *        Company:   * * =========================================================================== */#ifndef __PERSON_H__#define __PERSON_H__//定义一个命名空间namespace person{/** * 声明一个Person类 * 属性:name,age,weight,height */class Person{  public:    Person(const char *name,int age,int weight,int height);    ~Person();    void setName(const char* name);    char* getName() const;    void setAge(int age);    int getAge() const;    void setWeight(int weight);    int getWeight() const;    void setHeight(int height);    int getHeight() const;    void print();  private:    char* name;    int age;    int weight;    int height;};/* * *声明一个学生类 属性:sid,classNum * */class Student : public Person{  public:    Student(const char *name,int age,int weight,int height,int sid,int classNum);    ~Student();    void setClassNum(int classNum);    int getClassNum() const;    void setSid(int sid);    int getSid() const;    void print();  private:    int classNum;    int sid;};/* * *声明一个老师类属性:tid teachType * */class Teacher :public Person{  private:    int teachType;    int tid;  public:    Teacher(const char *name,int age,int weight,int height,int tid,int teachType);    ~Teacher();    void setTeacherType(int type);    int getTeacherType() const;    void setTid(int tid);    int getTid() const;    void print();};}#endif
#include<iostream>#include<stdio.h>#include<stdlib.h>#include"person.h"#include<string.h>using namespace::std;using namespace::person;namespace person{//======================Person类定义Person::Person(const char *m_name,int age,int weight,int height):age(age),weight(weight),height(height){    name = (char *)malloc(strlen(m_name) * sizeof(char));    strncpy(name,m_name,strlen(m_name)* sizeof(char));    cout<<"Person constructor"<<endl;}Person::~Person(){  if(name !=NULL){    free(name);    name = NULL;  }  cout<<"Person destructor"<<endl;}void Person::setName(const char* m_name){  if(name != NULL){    strncpy(name,m_name,strlen(m_name) * sizeof(char));  }}char* Person::getName() const{    return name;}void Person::setAge(int age){   age = age;}int Person::getAge() const{  return age;}void Person::setWeight(int weight){    weight = weight;}int Person::getWeight() const{   return weight;}void Person::setHeight(int height){   height = height;}int Person::getHeight() const{  return height;}void Person::print(){  cout<<"name:"<<name<<endl;  cout<<"age:"<<age<<endl;  cout<<"height:"<<height<<endl;  cout<<"weight:"<<weight<<endl;}//======================Student类定义Student::Student(const char *name,int age,int weight,int height,int sid,int classNum):Person(name,age,weight,height),sid(sid),classNum(classNum){  cout<<"Student constructor"<<endl;}Student::~Student(){  cout<<"Student destructor"<<endl;}void Student::setClassNum(int classNum){    classNum = classNum;}int Student::getClassNum() const{    return classNum;  }void Student::setSid(int sid){  sid = sid;   }int Student::getSid() const{  return sid;}//子类去重写父类的方法的时候,需要在子类中去进行声明,void Student::print(){  Person::print();//在子类中调用父亲的方法,类似与java中是super  cout<<"sid:"<<sid<<endl;  cout<<"classNum"<<classNum<<endl;}//=====================teacher类的定义    //注意:子类在继承父类的时候,如果需要用到父类中的构造函数的话,这个时候,需要采用默认初始化的形式//如:    :Person()//在初始化的时候需要去调用父类的构造函数Teacher:: Teacher(const char *name,int age,int weight,int height,int tid,int teacherType):Person(name,age,weight,height),tid(tid),teachType(teacherType){  cout<<"teacher constructor"<<endl;}Teacher::~Teacher(){  cout<<"teacher destructor"<<endl;}void Teacher::setTeacherType(int type){   teachType = type;}int Teacher::getTeacherType() const{  return teachType;}void Teacher::setTid(int tid){  tid = tid;}int Teacher::getTid() const{  return tid;}void Teacher::print(){  Person::print();  cout<<"teachType:"<<endl;  cout<<"tid:"<<endl;}}
#include<iostream>#include"person.h"using namespace::std;using namespace::person;int main(int argc,char *argv[]){  Student* stu = new Student("zhangsan",10,80,165,001,3);  stu->print();   Teacher* teacher = new Teacher("wanglaoshi",22,135,170,32,3);  teacher->print();  delete stu;  delete teacher;  return 0;}

以上简单代码的输出为:

Person constructorStudent constructorname:zhangsanage:10height:165weight:80sid:1classNum3Person constructorteacher constructorname:wanglaoshiage:22height:170weight:135teachType:tid:Student destructorPerson destructorteacher destructorPerson destructor

从以上的代码和输出结果中可以总结出:
1:子类继承父类,在创造子类对象的时候,是先去创建父类,然后再去创建子类,而在析构的时候是先去析构子类,然后再去析构父类
2:子类如果想去重写父类的方法的时候,子类同样需要声明重写的函数
3:子类在调用父类方法的时候采用的是类似

父类::方法();

4:子类构造函数中,如果需要用到父类相关属性的时候,需要先去调用父类的构造函数,初始化的时候可以采用默认初始化参数的形式,也可以采用在函数中去初始化的形式


私有继承与保护继承

私有继承:

在上面共有继承的时候,我们在继承的时候,采用的是public,公有的访问限制符,那么私有继承同样也是,类似于:

私有继承的访问限制符为privateclass Student::private Person{}

私有继承的子类不能做基类能做的所有事情,因此私有继承的子类与父类不是”is-a”的关系

私有继承主要是在语法上面是允许的
私有继承是不符合里式替换的原则(父类能出现的地方,子类一定能替换)

    /* * =========================================================================== * *       Filename:  privateExtendsTest.cpp *    Description:   *        Version:  1.0 *        Created:  2017年06月20日 22时44分53秒 *       Revision:  none *       Compiler:  gcc *         Author:   (),  *        Company:   * * =========================================================================== */#include<iostream>#include<stdio.h>#include<stdlib.h>#include<string>using namespace::std;class Animal{  public:     Animal(){      cout<<"animal constructor"<<endl;     }     ~Animal(){      cout<<"animal destructor"<<endl;     }     void setweight(int weight){       weight = weight;     }     void eat(){       cout<<"animal eat"<<endl;     } protected:     void drink(){       cout<<"animal drink"<<endl;     }  private:     int weight;};class Cat:private Animal{   public:     Cat(){       cout<<"cat constructor"<<endl;     }     ~Cat(){       cout<<"cat destructor"<<endl;     }     void setCatType(string catType){      catType = catType;      cout<<"cat type:"<<catType<<endl;     }     void drink(){      Animal::drink();      cout<<"cat drink milk"<<endl;     }     void eat(){      Animal::eat();      cout<<"cat eat meal"<<endl;     }   private:     string catType;};int main(int agrc,char *argv[]){   Cat cat;   cat.drink();   cat.setCatType("coffe cat");//1:基类的public和private成员都以private身份出现在派生类中,但是基类的private成员不可直接访问//2:派生类的成员函数可以直接访问基类中的public和protected成员,但是不能直接访问基类的private成员//3:通过派生类的对象不能访问基类中的任何成员   //cat.setweight(20);   cat.eat();  return 0;}

在以上的调用中出现了cat.setweight(20);的时候,这个时候系统在编译的时候会直接抛出以下错误,表示私有继承的类的对象是不能直接调用父类的函数的,而在继承的时候,派生类中可以调用父类中public,protected访问限制符号的函数或变量

privateExtendsTest.cpp: In functionint main(int, char**)’:privateExtendsTest.cpp:30:11: error: ‘void Animal::setweight(int)’ is inaccessible void setweight(int weight){           ^privateExtendsTest.cpp:77:20: error: within this context    cat.setweight(20);                    ^privateExtendsTest.cpp:77:20: error: ‘Animal’ is not an accessible base of ‘Cat’

保护继承:

保护继承也是一样,采用protected的访问限制符修饰

class Student::protected Person{}

总结:
不同的继承方式主要体现在:
1:子类成员对父类成员的访问权限
2:通过派生类对象对基类成员的访问权限

公有继承(最多):
1:基类的public和protected成员的访问属性在派生类中保持不变,但是基类的private成员不可以直接访问
2:派生类的成员函数可以直接访问基类中的public和protected成员,不能直接访问基类的private成员
3:通过派生类的对象只能访问基类的public成员

私有继承(很少):
1:基类的public和private成员都以private身份出现在派生类中,但是基类的private成员不可直接访问
2:派生类的成员函数可以直接访问基类中的public和protected成员,但是不能直接访问基类的private成员
3:通过派生类的对象不能访问基类中的任何成员

保护继承(很少):
1:基类的public和private成员都以protected身份出现在派生类中,但是基类的private成员不可直接访问
2:派生类的成员函数可以直接访问基类中的public和protected成员,但是不能直接访问基类的private成员
3:通过派生类的对象不能访问基类中的任何成员

继承访问控制表

继承类型\存取模式 public protected private public public protected private protected protected protected private private private private private

多重继承

可以为一个派生类指定多个基类,这样的继承结构被称为多重继承和多继承
到目前位置,所讨论的层次中,每个类都只去继承一个父类,但是在现实中,有些类却代表两个类的合成,如果一个java程序员有时候也需要去担任测试工程师的职责,这样的混合兼职形式

多重继承的形式:

 class Coder public:javaEngineer,public testEngineer{};

疑难点:
当两个父类有同样成员的时候,这个时候可能会带来模糊性,这个时候就需要将共有的成员抽取出去,派生类对象调用成员函数的时候,加上基类的声明如:

 Coder coder; Coder.javaEngineer::writeCode();
/* * =========================================================================== * *       Filename:  MultiInheritance.cpp *    Description: *    智能手机是继承了智能设备,现在的手机都能看电视,也继承了功能手机的打电话,发短信的功能 *        Version:  1.0 *        Created:  2017年06月20日 22时05分41秒 *       Revision:  none *       Compiler:  gcc *         Author:   (),  *        Company:   * * =========================================================================== */#include<iostream>#include<stdio.h>#include<stdlib.h>using namespace::std;class Tv{  public:    Tv(int t_width,int t_height):width(t_width),height(t_height){      cout<<"Tv constructor"<<endl;    }    ~Tv(){      cout<<"Tv destructor"<<endl;    }    void playVideo(){      cout<<"play video"<<endl;    }   void setwidth(int width){     width = width;   }  void setheight(int height){    height = height;  }  private:    int width;    int height;};class Phone{  public:    Phone(int p_width,int p_height):width(p_height),height(p_height){      cout<<"phone constructor"<<endl;    }    ~Phone(){      cout<<"phone destructor"<<endl;    }    void ring(){      cout<<"take ring"<<endl;    }    void receiverRing(){      cout<<"receive ring"<<endl;    }    void sendMessage(){      cout<<"sendMessage"<<endl;    }    void setheight(int height){      height = height;    }    void setwidth(int width){      width = width;    }  private:    int height;    int width;};class SmartPhone:public Tv,public Phone{  public:    SmartPhone():Phone(0,0),Tv(0,0){      cout<<"SmartPhone constructor"<<endl;    }    ~SmartPhone(){      cout<<"SmartPhone destructor"<<endl;    }  private:};int main(int argc ,char *argv[]){  SmartPhone smartPhone;  //因为此时Phone和Tv都是有width和height的,这个时候就需要去其调用的方法  //当然也是可以去将他们的width和height抽取出来,然后做最顶层的继承对象,  //如果将其抽取出来之后,可能就需要就需要采用虚拟继承vitural来优化内存结构  smartPhone.Phone::setwidth(1280);  smartPhone.Phone::setheight(720);  smartPhone.ring();  smartPhone.receiverRing();  smartPhone.sendMessage();  smartPhone.playVideo();  return 0;}
原创粉丝点击