C++学习:面向对象之继承
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 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:通过派生类的对象不能访问基类中的任何成员
继承访问控制表
继承类型\存取模式 | 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;
}