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;
//-- 上述是父类指针指向子类对象构成多态的调用;下述是父类引用引用一个子类对象构成的多态调用
Man m2;
HuMan &ph =m2;
ph.xuHanShuTestFunc2();
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;
}