基类指针/派生类指针
#include <iostream>
using namespace std;
class Human
{
public:
Human();
Human(int);
public:
int m_Age;
char m_Name[100];
public:
void func_human();
};
Human::Human()
{
cout << "Human::Human()" << endl;
}
Human::Human(int tmp)
{
cout << "Human::Human(int tmp)" << endl;
}
void Human::func_human()
{
cout << "void Human::func_human()" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
Men();
Men(int);
private:
public:
void func_man();
};
Men::Men()
{
cout << "Men::Men()" << endl;
}
Men::Men(int tmp)
{
cout << "Men::Men(int tmp)" << endl;
}
void Men::func_man()
{
cout << "void Men::func_man()" << endl;
}
int main()
{
Human* p_human = new Human();
Men* p_men = new Men();
//父类指针可以new子类对象,父类指针指向子类对象;反之不行;
Human* p_h = new Men();
p_h->func_human(); //父类类型指针调用父类的成员函数;
//p_h->func_man(); //错误,不可以,虽然是new子类对象,但是你是父类指针,不可以调用子类成员函数
//Men* p_m = new Human(); 子类指针无法父类对象;
//父类指针没有办法调用子类的成员函数,为什么还让父类指针new一个子类对象呢???
//借助虚函数
}
虚函数
#include <iostream>
using namespace std;
class Human
{
public:
Human();
Human(int);
public:
int m_Age;
char m_Name[100];
public:
void func_human();
virtual void eat();
};
Human::Human()
{
cout << "Human::Human()" << endl;
}
Human::Human(int tmp)
{
cout << "Human::Human(int tmp)" << endl;
}
void Human::func_human()
{
cout << "void Human::func_human()" << endl;
}
void Human::eat()
{
cout << "human eat food" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
Men();
Men(int);
private:
public:
void func_man();
virtual void eat();
};
Men::Men()
{
cout << "Men::Men()" << endl;
}
Men::Men(int tmp)
{
cout << "Men::Men(int tmp)" << endl;
}
void Men::func_man()
{
cout << "void Men::func_man()" << endl;
}
void Men::eat()
{
cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
Women();
Women(int);
private:
public:
void func_women();
virtual void eat();
};
Women::Women()
{
cout << "Women::Women()" << endl;
}
Women::Women(int tmp)
{
cout << "Women::Women(int tmp)" << endl;
}
void Women::func_women()
{
cout << "void Women::func_women()" << endl;
}
void Women::eat()
{
cout << "women eat miantiao" << endl;
}
int main()
{
/*
Human* p_h = new Men();
p_h->eat(); //调用的是父类的eat函数,因为phuman是父类指针;
//如何调用Men和Women中的eat()函数;
//1. 比较繁琐,定义多个指针来解决
Men* p_m = new Men();
p_m->eat(); //调用子类men的eat
Women* p_w = new Women();
p_w->eat(); //调用子类women的eat
*/
//2. 定义一个对象指针,就可以调用父类和各个子类的同名,同参函数
// 1). 这个对象指针,必须是父类指针;
// 2). 这个同名同参函数,父类中声明之前必须要加virtual;声明为虚函数;子类中不加也可以,一旦某个函数在父类中声明虚函数,子类继承后都是虚函数
// 子类中添加virtual可以增加可读性;函数重写,子类和父类的函数名、参数、返回值一样;
/*
Human* p_h = new Men();
p_h->eat(); //调用Men的虚函数,new的是什么调用什么;
delete p_h;
p_h = new Women();
p_h->eat(); //调用的是Women的虚函数
delete p_h;
p_h = new Human();
p_h->eat(); //调用的是Human的虚函数
delete p_h;
*/
//3. 不重新new,直接调用Human的虚函数;
/*
Human* p_h_1 = new Men();
p_h_1 -> eat(); //调用Men的虚函数
p_h_1->Human::eat(); //调用的是Human的虚函数
delete p_h_1;
*/
}
override
为了避免在子类中写错虚函数,在C++11中,可以在函数声明中添加override关键字;这个关键字用在子类中,而且是虚函数专用;override就是用来说明派生类中的虚函数,用了这个关键字,编译器会认为这个eat是覆盖了基类中的同名函数(只有虚函数才存在子类可以覆盖父类中同名函数的问题);那么编译器就会在父类中找同名同参的虚函数,如果没找到,编译器就会把报错;如果函数名,参数返回值写错了,编译器会帮忙纠错;
注意: 派生类的虚函数可以和基类的虚函数的返回值有差别;
final
也是虚函数专用,用在父类中,如果在父类的函数声明中加了final关键字;子类不能覆盖父类的该函数;
调用虚函数执行的还是“动态绑定”,动态:指的是在程序运行的时候才知道调用哪个函数;
多态性
只是针对虚函数来说的,随着虚函数的提出,面向对象的三大特性之一:多态性;
多态性:体现在具有继承关系的父类和子类之间,子类重新定义父类的成员函数,同时父类把该成员函数声明为virtual
通过父类的指针,只有到了程序运行的时候,找到动态绑定到父类指针上的对象,这个对象它有可能是某个子类对象,也可能是父类对象
然后系统内部实际上要查一个虚函数表,找到函数的入口地址,从而调用父类或者子类的函数;这就是运行时期的多态性;
纯虚函数
纯虚函数是在基类中声明的虚函数,但是在基类中没有定义;但是要求任何派生类都要定义该虚函数的实现方法;
基类中实现纯虚函数的方法是在函数原型后增加=0
注意:
- 成员函数有纯虚函数的类叫抽象类,不能用来生成对象,主要用来当做基类来生成子类用;
- 子类必须要完全实现该基类中定义的纯虚函数;
#include <iostream>
using namespace std;
class Human
{
public:
Human();
Human(int);
public:
int m_Age;
char m_Name[100];
public:
virtual void eat() =0;
};
Human::Human()
{
cout << "Human::Human()" << endl;
}
Human::Human(int tmp)
{
cout << "Human::Human(int tmp)" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
Men();
Men(int);
private:
public:
virtual void eat();
};
Men::Men()
{
cout << "Men::Men()" << endl;
}
Men::Men(int tmp)
{
cout << "Men::Men(int tmp)" << endl;
}
void Men::eat()
{
cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
Women();
Women(int);
private:
public:
virtual void eat();
};
Women::Women()
{
cout << "Women::Women()" << endl;
}
Women::Women(int tmp)
{
cout << "Women::Women(int tmp)" << endl;
}
void Women::eat()
{
cout << "women eat miantiao" << endl;
}
int main()
{
//抽象类,不能用来生成对象,主要用来统一管理子类对象
//Human h; //一旦一个类中有纯虚函数,不能生成这个类的对象了,不能实例化抽象类
//Human* p_h = new Human; 不合法
Human* p_m = new Men;
p_m->eat();
Human* p_w = new Women;
p_w->eat();
}
虚析构函数
基类的析构函数一般写成虚函数;
#include <iostream>
using namespace std;
class Human
{
public:
Human();
Human(int);
virtual ~Human();
public:
int m_Age;
char m_Name[100];
public:
virtual void eat() =0;
};
Human::Human()
{
cout << "Human::Human()" << endl;
}
Human::~Human()
{
cout << "Human::~Human()" << endl;
}
Human::Human(int tmp)
{
cout << "Human::Human(int tmp)" << endl;
}
//Men是Human的子类
class Men:public Human
{
public:
Men();
Men(int);
~Men();
private:
public:
virtual void eat();
};
Men::Men()
{
cout << "Men::Men()" << endl;
}
Men::~Men()
{
cout << "Men::~Men()" << endl;
}
Men::Men(int tmp)
{
cout << "Men::Men(int tmp)" << endl;
}
void Men::eat()
{
cout << "men eat mi" << endl;
}
//Women是Human的子类
class Women :public Human
{
public:
Women();
Women(int);
~Women();
private:
public:
virtual void eat();
};
Women::Women()
{
cout << "Women::Women()" << endl;
}
Women::~Women()
{
cout << "Women::~Women()" << endl;
}
Women::Women(int tmp)
{
cout << "Women::Women(int tmp)" << endl;
}
void Women::eat()
{
cout << "women eat miantiao" << endl;
}
int main()
{
//Men men;
Human* p_m = new Men;
delete p_m; //没有调用子类的析构函数
//总结:用基类指针 new子类的对象,在delete的时候,系统不会调用派生类的析构函数
//解决方法:
//把父类的析构函数写成虚函数
//在public继承中,基类对派生类以及起对象的操作,只能影响到哪些从基类继承下来的成员;
//如果想要用基类对非继承成员进行操作,则要把基类的这个函数定义为虚函数,析构函数也是这样;
//另外,基类中析构函数的虚属性也会被继承给子类,这样的话子类中的析构函数自然就成了虚函数,虽然名字跟基类的析构函数不同;
//detete puhuan; 肯定要调用父类的析构函数,但是在父类析构函数中它要想调用子类men的析构函数,那么
//human这个类的析构函数就要声明成virtual,也就是C++中的运行时多态,调用的函数必须是virtual的;
//结论
//如果一个类,想要做基类,一定要把这个类的析构函数写成虚析构函数;
//只要基类的析构函数是虚函数,能保证delete基类指针时候正确的运行析构函数版本;
//普通类不写析构函数,但是如果是基类,必须是虚析构函数;
}