1.1C的第一个程序1.多态的概念多态(polymorphism)的概念:通俗来说就是多种形态。多态分为编译时多态(静态多态)和运行时多态(动态多态)这里我们重点讲运行时多态编译时多态(静态多态)和运行时多态(动态多态)。编译时多态(静态多态)主要就是我们前面讲的函数重载和函数模板他们传不同类型的参数就可以调用不同的函数通过参数不同达到多种形态之所以叫编译时多态是因为他们实参传给形参的参数匹配是在编译时完成的我们把编译时一般归为静态运行时归为动态。 运行时多态具体点就是去完成某个行为(函数)可以传不同的对象就会完成不同的行为就达到多种形态。比如买票这个行为当普通人买票时是全价买票;学生买票时是优惠买票(5折或75折);军人买票时是优先买票。再比如同样是动物叫的一个行为(函数)传猫对象过去就是”(^w^)喵“传狗对象过去就是汪汪。2.多态的定义及实现2.1多态的构成条件多态是一个继承关系下的类对象去调用同一函数产生了不同的行为。比如Student继承了Person。Person对象买票全价Student对象优惠买票。2.1.1实现多态还有两个必须重要条件1.必须是基类的指针或者引用调用虚函数2.被调用的函数必须是虚函数并且完成了虚函数重写说明:要实现多态效果第一必须是基类的指针或引用因为只有基类的指针或引用才能既指向基类对象又指向派生类对象;第二派生类必须对基类的虚函数完成重写/覆盖重写或者覆盖了基类和派生类之间才能有不同的函数多态的不同形态效果才能达到。这里提到了新名词虚函数我先演示一下多态的基本使用下面再详细讲虚函数。这里就是实现了多态我们可以看到虽然func的参数是Person类型的引用但是结果却调用了子类中的虚函数。里面的原因就如func中所写的那样跟ptr没关系和ptr所指向的对象有关。指针和引用差不多这里我就不演示了。注意这两个条件缺一不可这里就是不符合第一个条件就没有构成多态此时就和ptr有关了调用BuyTicket函数就看的是调用的类型而ptr类型是Person故只会调用Person中的函数。2.1.2虚函数类成员函数前面加virtual修饰那么这个成员函数就称为虚函数。注意非成员函数不能加virtual修饰。上面例子中的BuyTicket函数就是虚函数。2.1.3虚函数的重写/覆盖虚函数的重写/覆盖:派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数类型完全相同)称派生类的虚函数重写了基类的虚函数。 注意:在重写基类虚函数时派生类的虚函数在不加virtual关键字时虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性)但是该种写法不是很规范不建议这样使用。上面子类中的BuyTicket就是对父类的重写这里注意重写/覆盖的是函数的实现部分就是括号里面的内容。接着上面不符合第二个条件这里就不符合第二个条件了此时的BuyTicket函数就不是虚函数构不成多态故还是调用父类的函数。这种也是不构成多态的virtual只能子类隐藏父类是不能隐藏的。讲到这我们来看一道题问以下程序输出结果是什么A.A-0 B.B-1 C.A-1 D.B-0 E.编译出错 F.以上都不正确大家可以思考一下这个问题的答案。答案选择B这里可能很多人都不理解这里面有俩个坑。第一个就判断这里到底是不是多态我们可以看到此时创建了一个子类对象通过子类对象去调用test函数。这里要注意继承并不是把父类的函数拷贝到子类在调用时先在子类查找找不到才会去父类去查找。而这个坑的难点就是test函数中的this指针到底是A*呢还是B*呢遵循上面的原则我们在子类没有找到test函数接着去父类找找到了既然要调用父类的test函数那this指针自然而然就是A*那既然是基类的指针来调用虚函数那么就构成多态。来到第二个坑这也是为什么这道题选B的原因。既然上面构成多态了那么指针指向的对象是子类对象就该调用子类里面的func函数正常来说应该是B-0但是我们上面写了虚函数的重载/覆盖只是针对函数实现部分所以只是把实现部分的func给重写了那么既然只针对实现部分那么参数部分的val就不会发生变化就还是默认的缺省值1.这里很多人出错就是被这个缺省值给误导了所以我们要牢记虚函数重载/覆盖只针对函数实现部分。有人会有疑惑那缺省值不是不一样吗怎么会构成虚函数重写呢 这个问题我们要看上面虚函数重写的概念是函数名返回值类型和参数类型皆相同里面是不包含缺省值的缺省值不同不影响。2.1.4虚函数重写的一些其他问题