c++学习总结(4):继承与多态

一、继承和派生

类有一种继承的方式,很有趣。一般继承是公有继承。
继承的方式有三种:公有继承(public),保护继承(protected),私有继承(private)。

.publicprotectedprivate
公有继承publicprotected不可见
保护继承protectedprotected不可见
私有继承privateprivate不可见

public:类的内部可以访问。类的外部可以访问
protected:类的内部可以访问。类的外部不能访问
private:类的内部可以访问。类的外部不能访问

如何恰当的使用public,protected和private为成员声明访问级别?
1、需要被外界访问的成员直接设置为public
2、只能在当前类中访问的成员设置为private
3、只能在当前类和子类中访问的成员设置为protected,protected成
员的访问权限介于public和private之间。

子类与父类之间的关系:
1.子类对象可以当作父类对象使用。
2.子类对象可以直接赋值给父类对象。
3.子类对象可以直接初始化父类对象.
4.父类指针可以直接指向子类对象
5.父类引用可以直接引用子类对象

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Parent
{
public:
	void printP() {
		cout << "a " << this->a << endl;
	}
	int a;
};

class Child :public Parent
{
public:
	void printC()
	{
		cout << "b = " << this->b << endl;
	}
	int b;
};

void myPrint(Parent *pp)
{
	pp->printP();
	
}

int main(void)
{
		Parent p;

		//Child c = p; //p对象填充不满c对象空间,

		Child c;

		Parent p = c;//c 对象所占用的内存空间 >= p对象占用空间 能够填充满p对象所需要空间。

		p = c;

	//	c.printP(); //c 能够当做父类 p 来使用。
	Parent *pp = NULL;//父类指针
	Child *cp = NULL;//子类指针
	Parent p;//父类对象
	Child c; //子类对象
	pp = &c;//c 内存布局能够满足父类指针的全部需求, 可以用一个儿子的对象地址给父类指针赋值。
	myPrint(&p);
	myPrint(&c);

	return 0;
}

二、子类与父类之间的构造函数与析构函数

1.在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初
始化.
2.在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清
理.

继承和组合并存,构造和析构原则是声明呢?
答案是:
先构造父类,再构造成员变量、最后构造自己
先析构自己,在析构成员变量、最后析构父类

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

class Parent
{
public:
	Parent()
	{
		cout << "Parent().." << endl;
		a = 0;
	}
	Parent(int a) {
		cout << "Parent(int)..." << endl;
		this->a = a;
	}
	~Parent() {
		cout << "~Parent" << endl;
	}
	int a;
};

class Child :public Parent
{
public:
	//在调用子类的构造函数时候,一定会调用父类的构造函数
	// 父类先构造,子类后构造。
	Child(int a, int b) :Parent(a)
	{
		cout << "Child(int, int)..." << endl;
		this->b = b;
	}

	void printC() {
		cout << "b = " << b << endl;
	}

	~Child() {
		cout << "~Child()..." << endl;
	}

	int b;
};

int main(void)
{
	Child c(10, 20);

	c.printC();

	return 0;
}
 

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

三、子类与父类成员重名

如果是父类中有一个成员,与子类中的变量重名,要怎么解决呢,看以下代码:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;


class Parent
{
public:
	Parent(int a) {
		this->a = a;
	}

	int a;
};

class Child :public Parent
{
public:
	Child(int p_a, int c_a) :Parent(p_a)
	{
		this->a = c_a;
	}

	void print()
	{
		cout << Parent::a << endl;//在子类中使用父类的a,需要添加作用域。
		cout << this->a << endl;//child's a
	}
	int a;
};


int main(void)
{
	Child c(10, 100);
	c.print();


	return 0;
}

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

四、多继承

在这里插入图片描述
一个类同时继承两个类。

五、虚继承 virtual

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则
在对该基类中声明的名字进行访问时,可能产生二义性
虚继承声明使用关键字 virtual

在这里插入图片描述
虚继承为了防止这种情况下,类C,继承类B的成员后,不清晰是从类B1中继承下来的,还是类B2中继承下来的。
下面看一个例子。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

//家具类
class Furniture
{
public:
	int m; //材质
};

//将父亲类继承爷爷类  改成虚继承, 防止儿子在多继承我的时候,出现爷爷中的变量会拷贝多份。
class Bed :virtual public Furniture
{
public:
	void sleep() {
		cout << "在床上睡觉" << endl;
	}
};


class Sofa :virtual public Furniture
{
public:
	void sit() {
		cout << "在沙发上休息" << endl;
	}
};

//沙发床
class SofaBed :public Bed, public Sofa
{
public:
	void SleepAndSit() {
		sleep();
		sit();
	}
};

int main(void)
{
	Bed b;
	b.sleep();

	Sofa s;
	s.sit();

	cout << " ------ " << endl;

	SofaBed sb;
	sb.SleepAndSit();

	sb.m = 100;//此时只有一个m
			   //sb.Bed::m = 100;
			   //sb.Sofa::m = 200;

	return 0;
}

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

六、多态

多态发生的条件:
1.要有继承
2.要有虚函数重写
3.要有父类指针(父类引用)指向子类对象

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>

using namespace std;


//岳不群
class Yuebuqun
{
public:
	Yuebuqun( string kongfu)
	{
		this->kongfu = kongfu;
	}

	virtual  void fight() //标识修饰一个成员方法是一个虚函数。
	{
		cout << "岳不群" << "使出了" << kongfu << "打人" << endl;
	}

	void print()
	{

	}

	string kongfu;
};

//林平之 继承了 岳不群
class Linpingzhi :public Yuebuqun
{
public:
	Linpingzhi(string kongfu) :Yuebuqun(kongfu)
	{

	}

	//如果说父类中有一个虚函数是fight( ), 子类如果去重写这个虚函数。
	void fight()
	{
		cout << "林平之" << "使出了" << kongfu << "打人" << endl;
	}

	void print()
	{

	}
};

class Linghuchong :public Yuebuqun
{
public:
	Linghuchong(string kongfu) :Yuebuqun(kongfu)
	{

	}

	void  fight()
	{
		cout << "令狐冲 " << "使用了" << kongfu << endl;
	}
};

//在全局提供一个打斗的方法
void fightPeople(Yuebuqun *hero)//Yuebuqun *hero = xiaopp;  Yuebuqun *hero = xiaoyy;
{
	cout << "调用打人的方法" << endl;
	hero->fight();//希望传递进来的如果是子类,调用子类的fight
			      //如果传递进来的是父类, 调用父类的fight
					//这种行为就是 多态行为。
}

//多态发生的三个必要条件:
//1. 要有继承。
//2. 要有虚函数重写。
//3. 父类指针或引用 指向 子类对象。

int main(void)
{
	Yuebuqun *xiaoyy = new Yuebuqun("葵花宝典");

	//xiaoyy->fight();



	Linpingzhi *xiaopp = new Linpingzhi("僻邪剑谱");
	//xiaopp->fight();

	Linghuchong *xiaoll = new Linghuchong("独孤九剑");

	 
	fightPeople(xiaoyy);
	fightPeople(xiaopp);
	fightPeople(xiaoll);
	//编译器默认做了一个安全的处理。 编译认为 不管传递时子类对象还是父类对象,
	//如果统一执行父类d方法 那么是一定可以被成功执行。

	delete xiaoyy;
	delete xiaopp;
	delete xiaoll;

	return 0;
}

七、虚析构函数

如果父类在堆上开辟空间。子类也在堆上开辟空间。
进行析构的时候,会先构造父类,在构造子类。再进行析构时,如果不是虚构造函数,子类无法析构掉,导致内存泄露。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace	std;
class A
{
public:
	A()
	{
		p = new char[20];
		strcpy(p,"obja");
		printf("A()\n");
	}
	virtual ~A()
	{
		delete[] p;
		printf("~A()\n");
	}
private:
	char *p;
};
class B : public A
{
public:
	B()
	{
		p = new char[20];
		strcpy(p, "objb");
		printf("B()\n");
	}
	~B()
	{
		delete[] p;
		printf("~B()\n");
	}
private:
	char *p;
};
class C : public B
{
public:
	C()
	{
		p = new char[20];
		strcpy(p, "objc");
		printf("C()\n");
	}
	~C()
	{
		delete[] p;
		printf("~C()\n");
	}
private:
	char *p;
};
//通过⽗类指针 把 所有的⼦类对象的析构函数 都执⾏⼀遍
//通过⽗类指针 释放所有的⼦类资源
void howtodelete(A *base)
{
	delete	base;
}
int	main()
{
	C	*myC = new	C;
	//delete myC;	//直接通过⼦类对象释放资源 不需要写virtual	
	howtodelete(myC);//通过⽗类的指针调⽤释放⼦类的资源
	return 0;
}

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

八、重载,重写,重定义

1.重载:一定是发生在同一个作用域下。
2.重定义:是发生在两个不同的类中,一个父类,一个子类。
(1)普通函数重定义
(2)虚函数重写

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值