C++继承

继承

概念:是类与类之间的一张关系。如果类A继承于类B,则把类B称为基类(父类),类A称为派生类(子类)。继承需要符合is-a的关系,基类更通用更抽象,派生类更特殊更具体。

继承目的

①提高代码的重要性,因为派生类会拥有基类的所有特性,所以当写派生的时候就没有必要把基类相同功能的代码再写一遍。
②提高代码的可拓展性。派生类可以在基类上添加新的代码,而且一个基类可以出现多个派生类。
简单的继承
公有继承的子类声明:
class 派生类名: public 基类名
{
//成员的声明
};

  1. vi Animal.h
#ifndef _ANIMAL_H
#define  _ANIMAL_H

class Animal
{
public:
	void breath();
	
};
#endif
  1. vi Animal.h
#include"Animal.h"
#include <iostream>
using namespace std;

void Animal::breath()
{
	cout<<"Animal  Breath"<<endl;
}
  1. vi main.h
#include"Animal.h"
#include"Predator.h"

int main(int argc,char **argv)
{
	Predator Predator;
	Predator.breath();//调用基类的函数
	Predator.eatMeat();//调用本身的函数
	return 0;
}
  1. vi Predator.h
#ifndef _PREDATOR_H
#define _PREDATOR_H
#include"Animal.h"

class Predator:public Animal//公有继承的子类声明
{
public:
	void eatMeat();
};

#endif
  1. vi Predator.cpp
#include"Predator.h"
#include <iostream>
using namespace std;

void Predator::eatMeat()
{
	cout<<"Predator eat Meat"<<endl;
}

运行结果
在这里插入图片描述

对象的构造和析构过程

任何对象在创建后都会调用构造函数,在销毁之前都会调用析构函数。
因为派生类对象除了本身成员之外还拥有基类的成员,所以派生类对象在创建时会调用父类的构造函数,销毁时会调用父类的析构函数。

派生类的构造函数

在定义派生类的构造函数是需要知道父类的构造函数,如果不能指定则会调用父类的无参结构函数。
派生类构造函数定义:
派生类名::派生类名(参照列表)
:基类名(基类构造函数参数列表),派生类成员(参数)…
{
}

  1. 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;
}
  1. . 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;
}
  1. 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:既能在当前类成员函数,子类成员函数中访问,也能通过当前类对象,子类对象访问。

  1. 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++;
}
  1. 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,…
{
//成员
}

  1. 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的位置可以互换

  1. 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
  1. 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)
{

}
  1. 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形成的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值