C++基础 封装 继承 多态、 父类的final关键字、子类的override关键字、构造 拷贝构造 析构的调用

2021/9/14 14:05:44

本文主要是介绍C++基础 封装 继承 多态、 父类的final关键字、子类的override关键字、构造 拷贝构造 析构的调用,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Human.h

#ifndef __HUMAN__
#define __HUMAN__

class HuMan
{
public:
	HuMan(char n[20], int a);
	//-- 一旦一个类 想要做父类,务必把这个类的析构函数写成虚函数。这样就能保证delete父类指针时能够调用正确的析构函数(即利用多态,先调用子类,再调用父类的析构函数)
	//-- 从而保证父类指针指向的子对象 内存被正确的释放。
	virtual ~HuMan();
	char name[20];
	int age;
	int hanShuFuGaiTestFunc();

	virtual void  xuHanShuTestFunc();
	virtual void  xuHanShuTestFunc2();

	//-- final关键字是用在父类中的虚函数的,父类中的虚函数用了final关键字就是让父类的虚函数不能被覆盖
	virtual void  xuHanShuTestFunc3() final;

	//-- 一旦有了纯虚函数,就不能实例化HuMan类型的对象了,纯虚函数也是虚函数 也支持多态的。含有纯虚函数的类叫做抽象类。
	virtual void chunXuHanShuTestFunc() = 0;
protected:
	
private:
};
#endif

HuMan.cpp

#include "stdafx.h"
#include "Human.h"
#include "iostream"
using namespace std;
HuMan::HuMan(char n[20], int a):age(a){
	strcpy_s(name, n);
//	name = (n),
	cout << "HuMan的构造函数" << "name=" << name << "  age=" << age<< endl;
}
HuMan::~HuMan(){
	cout << "HuMan的析构函数" << endl;
}

int HuMan::hanShuFuGaiTestFunc(){
	cout << "父类HuMan的hanShuFuGaiTestFunc函数" << endl;
	return 0;
}
void  HuMan::xuHanShuTestFunc(){
	cout << "父类HuMan的虚函数" << endl;
}
void  HuMan::xuHanShuTestFunc2(){
	cout << "父类HuMan的虚函数xuHanShuTestFunc2" << endl;
}

void  HuMan::xuHanShuTestFunc3(){
	cout << "父类HuMan的虚函数xuHanShuTestFunc3" << endl;
}


Man.h

#ifndef __MAN__
#define __MAN__
#include "stdafx.h"
#include "Human.h"
#include "Wepon.h"
//--Man 继承自 HuMan 
/*
public protected private 三种继承方式
public protected private也专用于类中的成员变量和成员函数
public: 可以被任意实体来访问。(比如在main.cpp 的main函数内可以直接拿类对象或指向类对象的指针 直接访问类中公共的成员变量和函数)
protected: 父子类之间的 成员函数 可以访问。
private: 本类的  成员函数  可以访问。
*/
class Man :public HuMan
{
public:
	Man(char name[20], int age, char sex, wepon w1);
	virtual ~Man();
	
	wepon w;

	void hanShuFuGaiTestFunc(int i);

	//-- 为了避免在子类中写错虚函数,C++11可在函数声明所在行末尾加 override关键字。(成员函数实现中不用加)
	//-- 这个关键字是用在子类中,并且是虚函数专用的, 与此关键字相对的还有一个叫final的关键字,final关键字是用在父类中的虚函数的,父类中的虚函数用了final关键字就是让父类的虚函数不能被覆盖。
	virtual void  xuHanShuTestFunc() override;

	//can not override final function 父类中的虚函数用了final关键字就是让父类的虚函数不能被覆盖
	//virtual void  xuHanShuTestFunc3() override;

	//-- 成员函数可以只有声明,没有定义,不会发生编译错误;但是虚函数有声明,必须要有定义,没有定义这会发生错误,是因为 父类指针在调用一个虚函数的时 执行的是动态绑定的虚函数。


	virtual void chunXuHanShuTestFunc() override;
protected:

private:
	char sex;
};
#endif

Man.cpp

#include "stdafx.h"
#include "Man.h"
#include "iostream"
using namespace std;
//-- 对于类 类型成员变量的初始化,能放在构造函数的初始化列表里进行的,千万不要放在函数体里来执行
Man::Man(char name[20], int age, char sex, wepon w1) :HuMan(name, age), w(w1), sex(sex){
	cout << "执行Man的构造=" << " name=" << name << "  age=" << age << "sex = " << this->sex << endl;
}
//-- 对象中的成员变量 并不是在析构函数的函数体里面销毁的,而是在函数执行完毕,由系统隐含销毁的。
Man::~Man(){
	cout << "子类Man析构" << endl;
}

void Man::hanShuFuGaiTestFunc(int i){
	cout << "子类Man的hanShuFuGaiTestFunc函数" << endl;
}

void  Man::xuHanShuTestFunc(){
	cout << "子类Man的虚函数" << endl;
}

void  Man::chunXuHanShuTestFunc(){
	cout << "子类Man纯虚函数的定义被调用,纯虚函数被定义才可以实例化子类" << endl;
}

Wepon.h

#pragma once
class wepon
{
public:
	wepon(char*n, int d);
	~wepon();

	wepon(const wepon& w);
	wepon& operator = (const wepon & w);
	char name[20];
	int damage;
protected:
	
private:

};


Wepon.cpp

#include "stdafx.h"
#include "iostream"
#include "Wepon.h"
using namespace std;
wepon::wepon(char*n, int d) :damage(d)
{
	strcpy_s(name, n);
	cout << "执行wepon的构造=" << " name=" << name << "  damage=" << damage << endl;
}

wepon::~wepon()
{
	cout << "weopn的析构" << endl;
}

wepon::wepon(const wepon& w){
	damage = w.damage;
	cout << "weopn的拷贝构造被调用" << endl;
}
wepon& wepon::operator = (const wepon & w){
	damage = w.damage;
	cout << "weopn的赋值运算符重载" << endl;
	return *this;
}

Main.cpp

// ConsoleApplicationC++jichu13.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
//#include "Human.h"
#include "Wepon.h"
#include "Man.h"
#include "iostream"
using namespace std;
void testXuHanShu(wepon * w1){
	cout << "==============测试虚函数" << endl;
	//char x[20] = "xiaphua";
	HuMan *p_Human = new Man("xiaphua", 22, 0, *w1);
	//-- 父类指针指向子类对象,父类写虚 子类重写,则它的表现是子类的,否则是父类的
	p_Human->xuHanShuTestFunc();
	//-- 只在父类声明并定义了xuHanShuTestFunc2函数
	p_Human->xuHanShuTestFunc2();

	//-- 显示调用父类的xuHanShuTestFunc
	p_Human->HuMan::xuHanShuTestFunc();
	//-- 在delete的时候会调用,HuMan的析构函数, 因为我们还要让基类部分占用内存也要释放掉, 所以可以利用多态,将基类析构写成虚析构,这样delete p_Human 就会先调用父类 再调用子类的析构函数了。
	delete p_Human;
	cout << "==============测试虚函数" << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
	char n[20] = "xiaoming";
	/*
	正常调用构造,析构函数。 new delete承对出现
	*/
	//HuMan *h1 = new HuMan(n, 22);
	//HuMan* h2 = new HuMan("xiaoewang", 33);
	//delete h1;
	//delete h2;

	wepon * w1 = new wepon("d", 5);    //--执行wepon的构造
	Man * m1 = new Man(n, 20, 1, *w1); //-- 首先传入实参*w1给形参时,调用wepon的拷贝构造,然后再执行man的构造,
	                                   //-- 在man构造函数的初始化列表执行human的构造,
	                                   //-- 在man构造函数的初始化列表执行 w(w1),调用wepon的拷贝构造,用来初始化 *m1对象的wepon类型成员w,(当m1 指向的内存被销毁,*m1对象的wepon类型的成员变量w也会被销毁,会调用wepon的析构函数)
	                                   //-- 在man构造函数的函数体执行完毕,执行完毕到 } 后执行wepon的析构,这个析构是函数的参数 wepon w1 局部变量 在函数执行完毕被销毁时出发的。

									   //-- 即:拷贝构造也属于构造函数,也存在对应的析构函数的调用。(自己总结:也许理解不精确,通常情况下 构造函数+拷贝构造数量 的调用次数 应该等于 析构函数的调用次数)


	cout << "w1->damage=" <<  w1->damage << endl;
	cout << "m1->w.damage=" <<  m1->w.damage << endl;
	w1->damage = 888;
	cout << "m1->w.damage=" << m1->w.damage << endl;


	//-- 在C++的继承中,子类会覆盖父类中的同名函数,不论此函数的返回值、参数。(父子类只要成员函数名相同,父类就会覆盖子类)
	m1->hanShuFuGaiTestFunc(1);
	//m1->hanShuFuGaiTestFunc(); NG
	m1->HuMan::hanShuFuGaiTestFunc(); //-- 因为函数是public 性质的,所以也可以这样显式访问该函数。
	getchar();

	testXuHanShu(w1);

	getchar();
	delete w1; //-- 执行wepon的析构
	delete m1; //-- 执行man的析构 ,因为m1对象有wepon类型成员,所以也要执行wepon的析构,最后执行父类的析构
	getchar();

	return 0;
}




这篇关于C++基础 封装 继承 多态、 父类的final关键字、子类的override关键字、构造 拷贝构造 析构的调用的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程