多态:意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。有了多态,可以有多个不同的类,都带有同一个名称但具有不同实现的函数,函数的参数甚至可以是相同的。形成多态必须具备三个条件:
- 1、必须存在继承关系;
- 2、继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字Virtual声明的函数,在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数);
- 3、存在基类类型的指针或者引用,通过该指针或引用调用虚函数;
虚函数: 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。虚函数声明如下:virtual ReturnType FunctionName(Parameter) 虚函数必须实现,如果不实现,编译器将报错。
纯虚函数:没有定义的虚函数是纯虚函数,在一个类中如果存在未定义的虚函数,那么不能直接使用该类的实例,可以理解因为未定义 virtual 函数,其类是抽象的,无法实例化。这和其它语言的抽象类,抽象方法是类似的——我们必须实现抽象类,否则无法实例化。(virtual 和 abstract还是有些区别的)。
1 #include <iostream> 2 using namespace std; 3 class Student 4 { 5 public: 6 Student(int a, int b) 7 { 8 parameter1 = a; 9 parameter2 = b; 10 } 11 12 virtual int Sum() //虚函数 13 { 14 cout << "基类" << endl; 15 return parameter1 + parameter2; 16 } 17 protected: 18 int parameter1; 19 int parameter2; 20 }; 21 22 class Math : public Student 23 { 24 public: 25 Math(int a, int b) : Student(a, b) {}; //使用基类的构造函数,须要在构造函数中显式声明 26 int Sum() 27 { 28 cout << "math -- " ; 29 return parameter1 + parameter2; 30 } 31 }; 32 33 class Chiness : public Student 34 { 35 public: 36 using Student::Student; //使用隐式的继承类的所有的构造函数。 37 int Sum() 38 { 39 cout << "chiness -- " ; 40 return parameter1 * parameter2; 41 } 42 }; 43 44 int main() 45 { 46 cout << "Hello, world!" << endl; 47 Student *std; 48 Math math(5, 6); //初始化构造函数 49 std = &math; 50 cout << std->Sum() << endl; //同名函数的不同实现 51 52 Chiness chiness(5, 6); 53 std = &chiness; //初始化构造函数 54 cout << std->Sum() << endl; //同名函数的不同实现 55 system("pause"); 56 return 0; 57 }
结果为:
Hello, world! math -- 11 chiness -- 30
上面代码中我们使用了构造函数的继承,在继承体系中,假设派生类想要使用基类的构造函数,须要在构造函数中显式声明。如:Math(int a, int b) : Student(a, b) {}; 假若基类用于拥有为数众多的不同版本号的构造函数。用上面的显示声明一个一个的继承就会很繁琐。所以我们通过using Student::Student的声明。将基类中的构造函数全继承到派生类中,更巧妙的是,这是隐式声明继承的。即假设一个继承构造函数不被相关的代码使用,编译器不会为之产生真正的函数代码,这样比透传基类各种构造函数更加节省目标代码空间。 但此时另一个问题:当使用using语句继承基类构造函数时。派生类无法对类自身定义的新的类成员进行初始化,我们可使用类成员的初始化表达式,为派生类成员设定一个默认初始值。所以我们必须初始化所有的类成员。