虚函数和多态

知识储备:

重提切片行为:

1.子类对象赋值给父类对象

2.父类型的指针指向了子类对象

3.父类型的引用引用子类的对象



虚函数:类的成员函数前面加virtual关键字,则这个成员函数称为虚函数

虚函数重写:当在子类的定义了一个与父类完全相同的虚函数时,则称子类的这个函数重写(也称覆盖)了父类的这个虚函数

构成多态需要满足的条件:

1.函数的形参是父类的指针或者引用

2.调用的Func必须是虚函数的重写

构成多态的函数的调用只与调用函数函数的对象有关,(父类对象还是子类对象)

常规的函数调用只与类型有关,(父类还是子类)

class Person
{
public:
	virtual void BuyTickets()
	{
		cout << " 全价" << endl;
	}
protected:
	string _name; // 姓名
};
class Student : public Person
{
public:
	virtual void BuyTickets()
	{
		cout << "半价" << endl;
	}
protected:
	int _num; //学号
};
//void Fun(Peron p)            //不构成多态,与类型有关,这里都调用的是基类的函数
//void Fun(Person* p)          //构成多态
void Fun(Person& p)		//构成多态
	// 不够多态的常规调用 -- 跟类型有关
	// 构成多态 -- 跟对象有关
	//构成多态的行为
	// 1.父类指针和引用
	// 2.调用的func必须是虚函数的重写
{
	p.BuyTickets();
}
void Test()
{
	Person p;
	Student s;
	Fun(p);
	Fun(s);
}

总结:

1. 派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外)

2. 基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性

3. 只有类的非静态成员函数才能定义为虚函数 静态成员函数不能定义为虚函数

4. 如果在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual。

5. 构造函数不能为虚函数,虽然可以将operator=定义为虚函数,但是最好不要将operator=定义为虚函数,因为容易使用时容易引起混淆。

6. 不要在构造函数和析构函数里面调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会发生未定义的行为。

7. 最好把基类的析构函数声明为虚函数。(why?析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里是因为编译器做了特 殊处理)

8.虚表是所有类对象实例共用的

class A                              //把基类的析构函数最好声明为虚函数
{
public :
	virtual ~A()
	{
		cout << "~A()" << endl;
	}
};

class B :public A
{
public:
	~B()
	{
		cout <<"~B()" << endl;
	}
};

int main()
{
	B b;
	A& ra = b;
	A* p = new B;		
	delete p; // p->destructor() + free(p)----只析构了A没析构B,如果~B()中有释放内存的操作,就会造成内存泄漏
                 //解决:将父类的析构函数定义成虚函数
                //这里先发生切片,A类型的指针p 指向了B对象,
	       //当将父类的析构写成虚函数,在实际调用的时候,构成多态与类型指针的类型无关,直接调B的析构
	system("pause");
	return 0;
}
纯虚函数:在成员函数的形参后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。

class Person
{
public:
	virtual void Display() = 0;                      //纯虚函数
protected:
	string _name;
};

class Teacher : public Person
{
	virtual void Display()
	{
		cout << "Teacher" << endl;
	}
protected:
	string _name;
};

class Student : public Person
{
	virtual void Display()
	{
		cout << "Student" << endl;
	}
protected:
	string _name;
};

int main()
{
	//Person p;                 //出错-抽象类无法创建对象
	Person* p = new Teacher;
	p->Display();

	p = new Student;
	p->Display();

	return 0;
}






猜你喜欢

转载自blog.csdn.net/bian_cheng_ru_men/article/details/80084582