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 function ‘int 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:通过派生类的对象不能访问基类中的任何成员
继承访问控制表
多重继承
可以为一个派生类指定多个基类,这样的继承结构被称为多重继承和多继承
到目前位置,所讨论的层次中,每个类都只去继承一个父类,但是在现实中,有些类却代表两个类的合成,如果一个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;}
- 【C#】面向对象之继承
- 用C实现面向对象之继承
- python语法学习面向对象之继承
- python语法学习面向对象之继承
- js进阶学习之--面向对象继承
- C++学习:面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 面向对象之继承
- 图-深度优先广度优先,以及邻接表的创建
- react native navigation 参数传递调用
- Guava之消息处理机制
- Thinkphp5学习(21)关联:一对一
- windows下安装TensorFlow(Win8 + Anaconda4.4 <python3.6>)
- C++学习:面向对象之继承
- js上拉加载
- poj 3311
- Date类型
- spring集成mina 实现消息推送以及转发
- 详解应对平台高并发的分布式调度框架TBSchedule
- 新闻客户端
- [实训]Java中FileUtils类的使用
- 【论文待读】Gcforest https://www.zhihu.com/question/56474891