更多知识点:C++知识点目录索引
接上一篇的c++知识点–继承
虚函数
概念
虚函数是指类的成员函数前加上virtual 关键字,此成员函数称之为虚函数
虚函数的作用
子类和父类的虚函数构成重写,可实现多态
虚函数重写
上一篇继承中提到重写的概念,当子类和父类定义了一个和父类完全相同的虚函数,则称子类的虚函数重写(覆盖)了父类的虚函数;
特殊情况:协变也可构成重写(注:协变指是指子类和父类中的虚函数的返回值为分别为子类指针和父类指针)
实例
虚函数重写:
协变:
什么是多态?
百度百科:
多态(Polymorphism)按字面的意思就是”多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述–多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自”Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在ObjectPascal和C++中都是通过虚函数实现的。
以上是百度百科的解释,下面给出自己的解释:
多态就是一个对象的多种形态,例如:我们只提供一个卖票窗口,在这个窗口可以买到成人票和学生票,将这个卖票的窗口看作一个对象,这个对象指向成人,那就买成人票,指向学生,就买学生票
C++中形成多态的条件
成员函数必须是虚函数
虚函数必须重写
使用对象的指针或引用调用重写的虚函数
对象调函数
不构成多态:
对象调函数与对象的类型有关,是哪个类型就调用哪个类型的函数
构成多态
跟指向的对象有关,指向哪个对象就调用哪个对象的函数
例子:
第一种情况:不构成多态
class Person
{
public:
void BuyTickets()
{
cout << "买票---全价" << endl;
}
protected:
string _name;
};
class Student:public Person
{
public:
void BuyTickets()
{
cout << "买票----半价" << endl;
}
protected:
int _num;
};
void Fun(Person& p)
{
p.BuyTickets();
}
int main()
{
Person p;
Student s;
Fun(p);
Fun(s);
system("pause");
return 0;
}
第二种情况:构成多态
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(Person& p)
{
p.BuyTickets();
}
int main()
{
Person p;
Student s;
Fun(p);
Fun(s);
system("pause");
return 0;
}
虚函数和多态的几点总结
派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同。(协变除外;协变是指基类和父类中含有函数名相同,参数列表相同,返回值类型不同的成员函数)
基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。
只有类的成员函数才能定义为虚函数。
静态成员函数不能定义为虚函数。
如果在类外定义虚函数,只能在声明函数时加virtual,类外定义函数时不能加virtual,这里是为了与第三条原则保持一致
构造函数不能为虚函数;
构成多态时,”使用对象指针或引用调用虚函数“里的对象指针必须是父类对象指针;
形成多态时,必须把基类的析构函数声明为虚函数。(为了防止内存泄漏)
抽象类(接口类)
在介绍抽象类之前先来看下纯虚函数:
纯虚函数是指在虚函数的后面写上 = 0;则成员函数为纯虚函数。
例如:
class AA
{
public:
virtual void Show() = 0;//纯虚函数
};
class BB : public AA
{};
上面实现了纯虚函数,那么抽象类指的就是类中的成员函数包含了纯虚函数,该类被称为抽象类。
抽象类的特点:
抽象类只能用作其他类的基类,不能建立抽象类对象。
抽象类不能用作参数类型、函数返回类型或显式转换的类型
可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。
抽象类的纯虚函数只声明不实现
例子:
class AA
{
public:
virtual void Show() = 0;
protected:
string _name;
};
class BB : public AA
{
public:
void Show(int a)//不构成重写
{
cout << "Show()" << endl;
}
};
int main()
{
AA aa;
BB bb;//不构成重写,BB继承了AA的特性,不能实例化出对象
}
class AA
{
public:
virtual void Show() = 0;
protected:
string _name;
};
class BB : public AA
{
public:
void Show()//BB的成员函数重写了AA的纯虚函数
{
cout << "Show()" << endl;
}
};
int main()
{
AA aa;
BB bb;//可以实例化出对象
}
友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
例:
class AA
{
friend void Show()
{
cout << "Show()" << endl;
}
protected:
string _name;
};
class BB:public AA
{
protected:
int _num;
};
void Show(AA& aa, BB& bb)
{
cout << aa._name << endl;
cout << bb._name << endl;
cout << bb._num << endl;
}
void Test()
{
AA aa;
BB bb;
Show(aa, bb);
}