继承
概念:是类与类之间的一张关系。如果类A继承于类B,则把类B称为基类(父类),类A称为派生类(子类)。继承需要符合is-a的关系,基类更通用更抽象,派生类更特殊更具体。
继承目的
①提高代码的重要性,因为派生类会拥有基类的所有特性,所以当写派生的时候就没有必要把基类相同功能的代码再写一遍。
②提高代码的可拓展性。派生类可以在基类上添加新的代码,而且一个基类可以出现多个派生类。
简单的继承
公有继承的子类声明:
class 派生类名: public 基类名
{
//成员的声明
};
- vi Animal.h
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
public:
void breath();
};
#endif
- vi Animal.h
#include"Animal.h"
#include <iostream>
using namespace std;
void Animal::breath()
{
cout<<"Animal Breath"<<endl;
}
- vi main.h
#include"Animal.h"
#include"Predator.h"
int main(int argc,char **argv)
{
Predator Predator;
Predator.breath();//调用基类的函数
Predator.eatMeat();//调用本身的函数
return 0;
}
- vi Predator.h
#ifndef _PREDATOR_H
#define _PREDATOR_H
#include"Animal.h"
class Predator:public Animal//公有继承的子类声明
{
public:
void eatMeat();
};
#endif
- vi Predator.cpp
#include"Predator.h"
#include <iostream>
using namespace std;
void Predator::eatMeat()
{
cout<<"Predator eat Meat"<<endl;
}
运行结果
对象的构造和析构过程
任何对象在创建后都会调用构造函数,在销毁之前都会调用析构函数。
因为派生类对象除了本身成员之外还拥有基类的成员,所以派生类对象在创建时会调用父类的构造函数,销毁时会调用父类的析构函数。
派生类的构造函数
在定义派生类的构造函数是需要知道父类的构造函数,如果不能指定则会调用父类的无参结构函数。
派生类构造函数定义:
派生类名::派生类名(参照列表)
:基类名(基类构造函数参数列表),派生类成员(参数)…
{
}
- vi Person.h Person.cpp
#ifndef _PERSON_H
#define _PERSON_H
class Person
{
private:
int weight
int hinght
public:
int getWeight()const;
int getHeight()const;
Person();//无参构造函数
Person(int weight,int height);//有参构造函数
};
#endif
Person.cpp
#include"Person.h"
#include<iostream>
using namespace std;
int Person::getWeight()const
{
return weight;
}
int Person::getHeight()const
{
return height;
}
Person:: Person()
{
cout<<" Person:: Person();"<<endl;
}
Person:: Person(int weight,int height)
weight(weight),height(height)
{
cout<<" Person:: Person(int weight,int height);"<<endl;
}
- . vi Student.h Student.cpp
#ifndef _STUDENT_H
#define _STUDENT_H
#include"Person.h"
class Student:public Person//person是父类,student是子类
{
private:
int id;
public:
int getId()const;
};
#endif
Student.cpp
#include"Student.h"
int Student::getId()const
{
return id;
}
- vi main.cpp
#include "Student.h"
#include"Person.h"
#include <iostream>
using namespace std;
int main(int arg,char **argv)
{
cout<<"Person: "<<sizeof(Person)<<endl;
cout<<"Student: "<<sizeof(Student)<<endl;
return 0;
}
运行结果
在main函数中添加Student stu;就会发现他会调用基类的无参结构函数
main.cpp
#include "Student.h"
#include"Person.h"
#include <iostream>
using namespace std;
int main(int arg,char **argv)
{
//cout<<"Person: "<<sizeof(Person)<<endl;
//cout<<"Student: "<<sizeof(Student)<<endl;
Student stu;
return 0;
}
运行结果
如果要指定调用构造函数,就需要在自己手动写出有参构造函数,如在Student.h公有成员中加入有参构造函数Student(int id,int weight ,int height)
Student.h
#ifndef _STUDENT_H
#define _STUDENT_H
#include"Person.h"
class Student:public Person//person是父类,student是子类
{
private:
int id;
public:
Student(int id , int weighet, int height);//有参构造函数
int getId()const;
};
#endif
Student.cpp
#include"Student.h"
int Student::getId()const
{
return id;
}
Student::Student(int id,int weight,int height)//有参构造函数
:Person(weight,height),id(id)//声明
{
cout<<"Student::Student(int,int,int)"<<endl;
}
main.cpp
#include "Student.h"
#include"Person.h"
#include <iostream>
using namespace std;
int main(int arg,char **argv)
{
//cout<<"Person: "<<sizeof(Person)<<endl;
//cout<<"Student: "<<sizeof(Student)<<endl;
//Student stu();
Student stu(1,70,170);//()里面就要写入参数了
return 0;
}
运行结果:这样就调用了父类的构造函数和子类的构造函数
访问控制符
private:只有能在当前类成员函数中能够访问。
protected:只有在当前类成员函数和子类成员函数中能够访问。
public:既能在当前类成员函数,子类成员函数中访问,也能通过当前类对象,子类对象访问。
- vi Object.h Object.cpp
#ifndef _OBJECT_H
#define _OBJECT_H
class Base
{
private:
int i;
protected:
int j;
public:
int k;
Base(int i,int j, int k);//基类对象
void testBase();//基类函数
};
class Child:public Base
{
public:
Child(int i,int j,int k);//子类对象
void testChid();子类函数
};
#endif
Object.cpp
#include"Object.h"
Base::Base(int i,int j,int k)
:i(i),j(j),k(k)
{
}
Child::Child(int i,int j,int k)
:Base(i,j,k)
{
}
void Child::testChild()//子类可以访问保护和公有成员
{
//i++;私有成员不能访问
j++;
k++;
}
void Base::testBase()//基类都能访问
{
i++;
j++;
k++;
}
- vi main.cpp
#include"Object.h"
int main(int argc,char **argv)
{
Base base(1,2,3);//基类对象,对象只能访问公开成员
//base.i++;私有成员不能访问
//base.j++;保护成员不能访问
base.k++;
Child child(1,2,3);//派生类对象
//child.i++;
//child.j++;
child.k++;
return 0;
}
受保护继承和私有继承
在C++中最常见的是公有继承,除了公有继承外,还有受保护继承和私有继承。
在受保护继承中,派生类从基类继承下来的私有成员会隐藏,所有非私有成员都会变成受保护成员。
在私有继承中,派生类从基类继承下来的私有成员会隐藏,所有非私有成员都会变成私有成员。
受保护继承的派生类声明和公有继承类似:
class 派生类名:protected 基类名
{
//成员
};
受保护继承的派生类声明和公有继承类似:**
class 派生类名:private 基类名
{
//成员
};
① 受保护的:vi Object.h Object.cpp main.cpp
#ifndef _OBJECT_H
#define _OBJECT_H
class Base
{
private:
int i;
protected:
int j;
public:
int k;
Base(int i,int j, int k);//基类对象
void testBase();//基类函数
};
class Child:protected Base//受保护的基类
{
public:
Child(int i,int j,int k);//子类对象
void testChid();子类函数
};
#endif
Object.cpp
#include"Object.h"
Base::Base(int i,int j,int k)
:i(i),j(j),k(k)
{
}
Child::Child(int i,int j,int k)
:Base(i,j,k)
{
}
void Child::testChild()//子类可以访问保护和公有成员
{
//i++;子类私有成员不能访问
j++;//变成受保护
k++;//变成受保护的
}
void Base::testBase()//基类都能访问
{
i++;
j++;
k++;
}
main.cpp
#include"Object.h"
int main(int argc,char **argv)
{
Base base(1,2,3);//基类对象,对象只能访问公开成员
//base.i++;私有成员不能访问
//base.j++;保护成员不能访问
base.k++;
Child child(1,2,3);//派生类对象
//child.i++;
//child.j++;
child.k++;
return 0;
}
②私有的vi Object.h Object.cpp main.cpp
#ifndef _OBJECT_H
#define _OBJECT_H
class Base
{
private:
int i;
protected:
int j;
public:
int k;
Base(int i,int j, int k);//基类对象
void testBase();//基类函数
};
class Child:private Base//私有的基类
{
public:
Child(int i,int j,int k);//子类对象
void testChid();子类函数
};
#endif
Object.cpp
#include"Object.h"
Base::Base(int i,int j,int k)
:i(i),j(j),k(k)
{
}
Child::Child(int i,int j,int k)
:Base(i,j,k)
{
}
void Child::testChild()//子类可以访问保护和公有成员
{
//i++;子类私有成员不能访问
j++;//变成受保护
k++;//变成受保护的
}
void Base::testBase()//基类都能访问
{
i++;
j++;
k++;
}
main.cpp
#include"Object.h"
int main(int argc,char **argv)
{
Base base(1,2,3);//基类对象,对象只能访问公开成员
//base.i++;私有成员不能访问
//base.j++;保护成员不能访问
base.k++;
Child child(1,2,3);//派生类对象
//child.i++;
//child.j++;
child.k++;
return 0;
}
注意:虽然私有和受保护用法一样,但是还是有区别的。当为私有时,child里面的j、k是变成私有的;当为受保护时,child里面的j、k是变成受保护的。
多重继承
在C++中,一个派生类可以继承自多个基类。
如下:
class 派生类:public基类A,public基类B,…
{
//成员
}
- vi Animal.h Animal.cpp main.cpp
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Bear
{
public:
void bearIntroduce();
};
class Raccon
{
public:
void racconIntroduce();
};
class Panda:public Bear,public Recccon//熊猫有熊和浣熊的特性
{}
public:
void pandaIntroduce();
};
Animal.cpp
#include" Animal.h"
#include <iostream>
using namespace std;
void Bear::bearIntroduce()
{
cout<<"I'm bear"<<endl;
}
void Raccoon::raccoonIntroduce()
{
cout<<"I'm raccoon"<<endl;
}
void Panda::pandaIntroduce()
{
cout<<"I'm panda"<<endl;
Bear::bearIntroduce();//调用基类Bear成员
Raccoon::raccoonIntroduce();
}
main.cpp
#include" Animal.h"
int main(int argc,char **argv)
{
Panda panda;
Panda.PandaIntroduce();//I'm panda I'm bear I'm raccoon
Panda.bearIntroduce();//I'm bear
Panda.raccoonIntroduce();//I'm raccoon
return 0;
}
运行结果
虚拟继承
概念:是多重继承中特有的概念,是为了解决多重继承出现的菱形继承。
比如:熊猫继承类熊、浣熊,而熊和浣熊都继承动物为,那么熊猫就会两次出现在动物中成员。为了节省内存,可以将熊、浣熊对动物的继承定义为虚拟继承,这样在熊和浣熊出现的继承体系中只会出现一份动物实例。
虚拟继承的语法:
class 派生类:virtual public基类
{
//成员
};
注意:public和virtual的位置可以互换。
- vi vi Animal.h Animal.cpp main.cpp
Animal.h
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
private:
int weight;
int age;
public:
Animal(int weight,int age);
};
class Bear:public Animal
{
public:
void bearIntroduce();
Bear(int weight,int age);
};
class Raccoon:public Animal
{
public:
void raccoonIntroduce();
Raccoon(int weight,int age);
};
class Panda:public Animal
{
public:
void PandaIntroduce();
Panda(int weight,int age);
};
#endif
- Animal.cpp
#include" Animal.h"
#include <iostream>
using namespace std;
void Bear::bearIntroduce()
{
cout<<"I'm bear"<<endl;
}
void Raccoon::raccoonIntroduce()
{
cout<<"I'm raccoon"<<endl;
}
void Panda::pandaIntroduce()
{
cout<<"I'm panda"<<endl;
Bear::bearIntroduce();//调用基类Bear成员
Raccoon::raccoonIntroduce();
}
//构造函数
Animal::Animal(int weight,int age)
:weight(weight),age(age)
{
}
Bear::Bear(int weight,int age)
:Animal(weight,age)
{
}
Raccoon::Raccoon(int weight,int age)
:Animal(weight,age)
{
}
Panda::Panda(int weight,int age)
:Bear(weight,age),Raccoon(weight,age)
{
}
- main.cpp
#include"Animal.h"
#include <iostream>
using namespace std;
int main(int arg,char **argv)
{
cout<<"Animal: "<<sizeof(Animal)<<endl;
cout<<"Bear: "<<sizeof(Bear)<<endl;
cout<<"Raccoon: "<<sizeof(Raccoon)<<endl;
cout<<"Panda: "<<sizeof(Panda)<<endl;
Panda panda(50,5);
panda pandaIntroduce();
return 0;
}
运行结果
从结果中我们可以看出Bear和Raccoon 继承了Animal的字节大小;Panda是继承了Bear和Raccoon它们两个字节的大小。这样就会造成资源浪费,所以我们要在Bear和Raccoon 的函数中加个virtual,并且Panda中之前调用Bear和Raccoon 后面补充Animal调用。
Animal.h
#ifndef _ANIMAL_H
#define _ANIMAL_H
class Animal
{
private:
int weight;
int age;
public:
Animal(int weight,int age);
};
class Bear:virtual public Animal//虚拟继承
{
public:
void bearIntroduce();
Bear(int weight,int age);
};
class Raccoon:virtual public Animal
{
public:
void raccoonIntroduce();
Raccoon(int weight,int age);
};
class Panda:public Animal
{
public:
void PandaIntroduce();
Panda(int weight,int age);
};
#endif
Animal.cpp
#include" Animal.h"
#include <iostream>
using namespace std;
void Bear::bearIntroduce()
{
cout<<"I'm bear"<<endl;
}
void Raccoon::raccoonIntroduce()
{
cout<<"I'm raccoon"<<endl;
}
void Panda::pandaIntroduce()
{
cout<<"I'm panda"<<endl;
Bear::bearIntroduce();//调用基类Bear成员
Raccoon::raccoonIntroduce();
}
//构造函数
Animal::Animal(int weight,int age)
:weight(weight),age(age)
{
}
Bear::Bear(int weight,int age)
:Animal(weight,age)
{
}
Raccoon::Raccoon(int weight,int age)
:Animal(weight,age)
{
}
Panda::Panda(int weight,int age)
:Animal(weight,age)//还要调用Animal构造函数(虚拟继承时)
:Bear(weight,age),Raccoon(weight,age)
{
}
运行结果
因为加了virtual所以占了4字节,所以Bear和Raccoon才有8变成了12,Panda的字节因为有了virtual才没有把Bear和Raccoon两个字节相加,而是在12字节上加了4字节,并不是之前的8+8形成的