虚函数
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//动态绑定:当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定。
//我们知道运行时才能知道到底调用了哪个版本的函数。
class A {
public:
virtual void getX() {
cout << "基类" << endl;
}
};
class B : public A{
public :
virtual void getX() {
cout << "派生类" << endl;
}
};
int main()
{
A* cycle;
A a;
B b;
cycle = &b;
cycle->getX();
}
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//动态绑定:当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定。
//我们知道运行时才能知道到底调用了哪个版本的函数。
class A {
public:
virtual void getX() {
cout << "基类" << endl;
}
};
class B : public A{
public :
virtual void getX() {
cout << "派生类" << endl;
}
};
int main()
{
A* cycle;
A a;
B b;
cycle = &b;
cycle->getX();
}
运行结果:派生类。
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
//动态绑定:当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定。
//我们知道运行时才能知道到底调用了哪个版本的函数。
class A {
public:
void getX() {
cout << "基类" << endl;
}
};
class B : public A{
public :
void getX() {
cout << "派生类" << endl;
}
};
int main()
{
A* cycle;
A a;
B b;
cycle = &b;
cycle->getX();
}
运行结果:基类。
可以看成 类型永远是最开始定义的class A ,指向b相当于b给了cycle指针的一个接口,所以可以访问B。
这个简单的小例子展示了普通函数与虚函数的区别。
当某个虚函数通过指针或引用调用时,编译器产生的代码直到运行时才能确定应该调用哪个版本的函数。改变指针的指向可实现不同的功能,无需从新定义。
#include "stdafx.h"
#include <iostream>
#include <cmath>
#define PI 3.1415926
using namespace std;
//基类 抽象类 公有派生3个类
class CFigure {
public:
virtual const char* FigureTyel() = 0;
virtual double Circumference() = 0;
virtual double Area() = 0;
virtual ~CFigure(){ }
};
class CTriangle : public CFigure {
private:
double a, b, c;
public:
CTriangle() {
a = b = c = 0;
}
CTriangle(double a , double b , double c ):a(a),b(b),c(c){ }
virtual const char* FigureTyel() {
return "Triangle";
}
virtual double Circumference() {
return a + b + c;
}
virtual double Area() {
double S = Circumference() / 2;
return sqrt(S*(S - a)*(S - b)*(S - c));
}
};
class CSquare : public CFigure{
private:
double a, b, c;
public:
CSquare() {
a = b = 0;
}
CSquare(double a , double b ) :a(a),b(b) { }
virtual const char* FigureTyel() {
return "Square";
}
virtual double Circumference() {
return 2 * a + 2 * b;
}
virtual double Area() {
double S = Circumference() / 2;
return a * b;
}
};
class CCircle : public CFigure {
private:
double r;
public:
CCircle() {
r = 0;
}
CCircle(double r) :r(r) { }
virtual const char* FigureTyel() {
return "CCircle";
}
virtual double Circumference() {
return 2 * r * PI;
}
virtual double Area() {
return r * r * PI;
}
};
int main()
{
//每个对象指向不同的类 从而实现动态绑定 在运行时确认调用的是哪一个函数。
CFigure* figures[3];
figures[0] = new CTriangle(2.1, 3.2, 4.3);
figures[1] = new CSquare(1.1, 2.2);
figures[2] = new CCircle(8.8);
for (int i = 0; i < 3; i++) {
cout << "FigureTyel : " << figures[i]->FigureTyel() << " Circumference : " << figures[i]->Circumference()
<< " Area : " << figures[i]->Area() << endl;
}
}
只用函数声明为虚函数,且通过指针或引用访问才能使用动态绑定。
/*****************************************分割线*****************************************/
#include "pch.h"
#include <iostream>
using namespace std;
class Basic {
public:
Basic() { }
virtual void whom() {
cout << "我是Basic类" << endl;
}
};
class Child : public Basic{
public:
Child(){ }
void whom() {
cout << "我是Child类" << endl;
}
};
int main()
{
//基类的对象
Basic basic;
cout << "1: "; basic.whom();
Basic* p_basic = &basic; //基类指针
cout << "2: "; p_basic->whom();
//派生类对象
Child child;
cout << "3: "; child.whom();
p_basic = &child; //基类指针指向派生类
cout << "4: "; p_basic->whom();
// Child* p = new Child();
// p->whom();
// p = &basic; //子类指针不能指向 父类
return 0;
}
首先这里的基类中whom函数是虚函数 在子类中重写
如果不是虚函数 运行结果如下
如果不是虚函数 基类指针父类指针指向子类对象时,访问的全部都是父类的同名成员函数。类型没有变化,即使基类指针指向派生类对象 通过这个指针调用的还是基类函数
加上virtual后
下面记录一下指针指向的类型的说明 :
可见 一个指针只能指向同类型的地址 非要☞可以强制转换
在类的继承中 允许基类指向派生类 反之不行
下面解释一下基类和派生类中同名函数的关系:
同名函数的重载动作,只发生在自由函数(即非成员),及同一个class/struct内部的函数之间。而不能跨越基类和派生类。当派生类写一个和基类同名(无论参数列表相同或不相同)的函数时,此时发生的动作叫“隐藏”。隐藏的意思,就是基类的同名函数,在派生类内,将变得无法直接调用(但可以间接调用)。
因为派生类继承了基类的所有函数和变量 如果派生类中有一个和基类同名的成员函数 那么原来在基类继承过来成员函数会被派生类的同名成员函数隐藏掉 但是基类中的同名函数功能不变
https://www.cnblogs.com/Newdawn/p/4972687.html
这篇文章很好的解释了 为什么基类和派生类在不是虚函数的情况下不能重载.
重写 重载 重定义(隐藏)的区别:
https://www.cnblogs.com/DannyShi/p/4593735.html