欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-15 16:50:38
...

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 constructor
Student constructor
name:zhangsan
age:10
height:165
weight:80
sid:1
classNum3
Person constructor
teacher constructor
name:wanglaoshi
age:22
height:170
weight:135
teachType:
tid:
Student destructor
Person destructor
teacher destructor
Person destructor

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

父类::方法();

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


私有继承与保护继承

私有继承:

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

私有继承的访问限制符为private
class 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;
}