多态分为
定义:虚函数是一个类的成员函数。
语法:virtual 返回类型 函数名参数列表()
关键virtual指明该成员为虚函数,仅用在类的定义中,如果虚函数在类外定义可以不加virtual。
当某一个类的成员函数被定义为虚函数,那么由该类派生出来的所有派生类,该函数都保持虚的特征。
class Animal
{
private:
string name;
public:
Animal(const string& na) : name(na) {}
public:
virtual void eat() {}
virtual void walk() {}
virtual void PrintInfo() {}
string& get_name() { return name; }
const string& get_name()const { return name; }
};
class Dog : public Animal
{
private:
string owner;
public:
Dog(const string& ow, const string& na) : Animal(na), owner(ow) {}
virtual void eat() { cout << "Dog eat: bone" << endl; }
virtual void walk() { cout << "Dog walk: run" << endl; }
virtual void PrintInfo()
{
cout << "Dog owner 's name: " << owner << endl;
cout << "Dog name: " << get_name() << endl;
}
};
class Cat : public Animal
{
private:
string owner;
public:
Cat(const string& ow, const string& na) : Animal(na), owner(ow) {}
virtual void eat() { cout << "Cat eat: fish" << endl; }
virtual void walk() { cout << "Cat walk: silent" << endl; }
virtual void PrintInfo()
{
cout << "Cat owner 's name: " << owner << endl;
cout << "Cat name: " << get_name() << endl;
}
};
//如果派生类传递基类的引用或指针,再以基类指针调用虚函数
void fun(Animal& animal)
{ //指针*animal
animal.eat();
animal.walk();
animal.PrintInfo();
}
int main(void)
{
Dog dog("嘟嘟", "哈士奇");
Cat cat("baiU", "喵酱");
fun(dog);
fun(cat);
return 0;
}
1.必须使用公有继承
2.类中的类方法必须是虚函数
3.要实现运行时的多态,必须用指针或者引用来调用虚函数。
原因:因为私有继承不代表是一个的意思)就是外部函数无法访问派生类的私有和保护属性。比如:猫是动物的一种。
//这是函数的重载。
class Object
{
public:
virtual Object*fun() {}
};
class Base
{
public:
virtual Base*fun(){}
}
void fun(Animal& animal)
{ //指针*animal
animal.eat(); //&amimal就是基类引用
animal.walk();
animal.PrintInfo();
}
实际上,运行时的多态是因为虚函数表的存在,如果设计的类中有虚函数,那么在编译阶段就会生成虚函数指针和虚函数表,里面存放了各个虚函数的函数指针。
如果派生类重写了基类的虚函数,那么派生类的虚函数就覆盖虚函数表里的基类虚函数。
class Object
{
private:
int value;
public:
Object(int x = 0) :value(x) {}
virtual void add() { cout << "object::add" << endl; }
virtual void fun() { cout << "object::fun" << endl; }
};
class Base :public Object
{
private:
int sum;
public:
Base(int x = 0) :Object(x + 10), sum(x) {}
virtual void add() { cout << "Base::add" << endl; }
virtual void fun() { cout << "Base::fun" << endl; }
};
int main()
{
Base base(10);
Object* op = &base;
return 0;
}
1.首先base调用构造函数,发现继承了Object,因此会先调用基类的构造函数,构造隐藏基类对象。
2.在构造时发现,基类中有虚函数,就会在隐藏基类对象中生成指向基类中虚函数的指针(vfptr)。如下图:
隐藏基类对象的虚表指针vfptr指向的基类的虚表


3.接下来返回Base类中,调用构造函数,构建base对象,发现Base类中也有虚函数。
4.接下来就会让隐藏基类对象中的vfptr指针指向派生类的虚函数表。(虚函数函数在数据区只有一份)
如下图:
隐藏基类对象的虚表指针指向派生类的虚表。
如果重写基类的虚函数,就会覆盖基类的虚函数。


如果使用"对象.函数名()",不管方法是否是虚函数,都调用该对象的方法。
如果使用基类的指针或者引用指向派生类,那么调用的虚方法时,会采用动态联编,调用派生类的虚方法。
(换句话说,基类指针和引用是通过基类的虚表指针查虚表的方式,实现动态绑定)
Object* op = &base;
基类指针指向base对象,Base类中有隐藏基类对象和base对象两个成员,隐藏基类对象内存中的虚表指针,指向Base类中的虚表。

int main()
{
Base base(10);
Object* op = &base;
op->add();
op->fun();
op->printf();
return 0;
}

op->add();

执行这一步时:

会跳转到这:

op->fun();
前两步操作和op->fun()相同,从edx中取地址,要加4个字节,取的是虚表中第二个函数的地址。
(edx+4),因为在虚表中存放的是虚函数指针。

class Object
{
private:
int value;
public:
Object(int x = 0) : value(x) {}
virtual void add() { cout << "Object::add" << endl; }
virtual void fun() { cout << "Object::fun" << endl; }
virtual void Print() { cout << "Object::Print" << endl; }
};
class Base : public Object
{
private:
int sum;
public:
Base(int x = 0) : Object(x + 10), sum(x) {}
virtual void add() { cout << "Base::add" << endl; }
virtual void fun() { cout << "Base::fun" << endl; }
virtual void show() { cout << "Base::show" << endl; }
};
class test :public Base
{
private:
int num;
public:
test(int x = 0) : Base(x + 10), num(x) {}
virtual void add() { cout << "Base::add" << endl; }
virtual void fun() { cout << "Base::fun" << endl; }
virtual void show() { cout << "Base::show" << endl; }
};

文字描述:
在Object类中可以看见三个虚函数:
virtual void add()
virtual void fun()
virtual void Print()
在Base中可以看到四个虚函数
virtual void add()
virtual void fun()
virtual void Print()
virtual void show()
在Test中可以看到四个虚函数
virtual void add()
virtual void fun() //是继承Base的,Object的被覆盖了
virtual void Print()
virtual void show()
而虚表指针是在Object类的隐藏基类对象的内存空间中。指向的是Test类中的虚表。
创建基类指针:
int main()
{
Test t1(10);
Object*op;
Base*bp;
Test*tp;
op = &t1;
bp =&t1;
tp = &t1;
}


均能访问到。
class Object
{
private:
int value;
public:
Object(int x = 0) : value(x) {}
virtual void add() { cout << "Object::add" << endl; }
virtual void fun() { cout << "Object::fun" << endl; }
virtual void Print() { cout << "Object::Print" << endl; }
void function()
{
fun();
}
};
int main(void)
{
Test t1;
Base b1;
Object obj;
t1.function();
b1.function();
obj.function();
return 0;
}
执行完:
Test t1;
Base b1;
Object obj;
t1, b1, obj的虚表状态。

当执行 t1.function();,this指针里的虚表指针指向的是Test类中的虚表,查询虚表,调用虚函数fun(),如下图:


执行b1.function();和1一样。

执行obj.function()也和1一样。

结果:
