(1)必须通过基类的指针或者引用调用虚函数。
(2)被调用的函数,必须是虚函数,且派生类必须对基类的虚函数进行重写。
class Animal
{
public:
virtual void eat()
{
cout << "吃草或者肉" << endl;
}
};
#include
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "吃草或者吃肉" << endl;
}
};
class Dog : public Animal
{
public:
virtual void eat()
{
cout << "吃肉" << endl;
}
};
int main()
{
cout << "当不是基类的指针或引用时:" << endl;
Animal a;
a.eat();
Dog d;
d.eat();
a = d;
cout << endl;
cout << "当通过的是基类的指针或引用时:" << endl;
Animal a2;
a2.eat();
Dog d2;
Animal* ap = &a2;
ap->eat();//调用的是父类的
ap = &d2;//通过基类的引用或指针
ap->eat();//构成重写。调用的是子类的。
}
(1)重写的协变(基类和派生类虚函数的返回值类型不同)
#include
using namespace std;
class A
{};
class B : public A
{};
class Animal
{
public:
virtual A* eat()
{
cout << "new A: 吃草或者吃肉" << endl;
return new A;
}
};
class Dog : public Animal
{
public:
virtual B* eat()
{
cout << "new B: 吃肉" << endl;
return new B;
}
};
int main()
{
cout << "当不是基类的指针或引用时:" << endl;
Animal a;
a.eat();
Dog d;
d.eat();
a = d;
cout << endl;
cout << "当通过的是基类的指针或引用时:" << endl;
Animal a2;
a2.eat();
Dog d2;
Animal* ap = &a2;
ap->eat();
ap = &d2;//通过基类的引用或指针
ap->eat();//构成重写
}
(2)析构函数的重写
#include
using namespace std;
class Animal
{
public:
virtual ~Animal()
{
cout << "~Animal()" << endl;
}
};
class Dog : public Animal
{
public:
virtual ~Dog()
{
cout << "~Dog()" << endl;
}
};
int main()
{
Animal* a = new Animal;
delete a;
cout << endl;
Dog* d = new Dog;
delete d;
cout << endl;
Animal* ap = new Dog;
delete ap;
return 0;
}
(1)概念:在虚函数后面写上=0,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数体现了接口继承。
(2)作用:① 强制派生类必须重写该虚函数。② 普通函数的继承是一种实现继承。虚函数的继承是一种接口继承(派生类继承的是基类虚函数的接口,目的是为了重写,只需要函数的接口,不需要函数的实现,达成多态)。如果不实现多态,不要把函数定义成虚函数。
(3)什么时候会使用抽象类?-------若要定义的基类非常抽象。
#include
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "吃肉或吃草" << endl;
}
virtual void fun1()
{
cout << "Animal::fun1()" << endl;
}
void fun2()
{
cout << "Animal::fun2()" << endl;
}
private:
double _d;
char _c;
int _i = 1;
};
int main()
{
Animal a;
cout << "sizeof(a) = " << sizeof(a) << endl;
return 0;
}
(1)
#include
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "吃肉或吃草" << endl;
}
virtual void fun1()
{
cout << "Animal::fun1()" << endl;
}
void fun2()
{
cout << "Animal::fun2()" << endl;
}
private:
double _d;
char _c;
int _i = 1;
};
class Dog : public Animal
{
public:
virtual void eat()
{
cout << "吃肉" << endl;
}
virtual void fun1()
{
cout << "Dog::fun1()" << endl;
}
};
int main()
{
Animal a;
Dog d;
cout << "sizeof(a) = " << sizeof(a) << endl;
cout << "sizeof(d) = " << sizeof(d) << endl;
return 0;
}
(2)
#include
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "吃肉或吃草" << endl;
}
virtual void fun1()
{
cout << "Animal::fun1()" << endl;
}
void fun2()
{
cout << "Animal::fun2()" << endl;
}
private:
double _d;
char _c;
int _i = 1;
};
class Dog : public Animal
{
public:
virtual void eat()
{
cout << "吃肉" << endl;
}
virtual void fun1()
{
cout << "Dog::fun1()" << endl;
}
};
int main()
{
Animal a;
Dog d;
Animal* ap = &a;
ap->eat();//调用的是Animal中的eat()
ap->fun1();//调用的是Animal中的fun1()
ap->fun2();
cout << endl;
ap = &d;
ap->eat();//调用的是Dog中的eat()
ap->fun1();//调用的是Dog中的fun1()
return 0;
}
(3)
int main()
{
Animal a;
Dog d;
a = d;//此时不构成多态,因为是通过基类的对象。
a.eat();
a.fun1();
return 0;
}
// 函数重载(静态绑定)例子
#include
using namespace std;
int main()
{
int i = 10;
double d = 99.9;
cout << a << endl;
cout << d << endl;
return 0;
}
#include
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "吃肉或吃草" << endl;
}
virtual void fun2()
{
cout << "Animal::fun2()" << endl;
}
private:
int _i;
};
class Dog : public Animal
{
public:
virtual void eat()
{
cout << "吃肉" << endl;
}
virtual void dun()
{
}
virtual void fun3()
{
}
private:
int _a;
};
int main()
{
Animal a;
Dog d;
return 0;
}
#include
using namespace std;
class A
{
public:
virtual void fun1()
{}
virtual void funA()
{}
};
class B
{
public:
virtual void fun2()
{}
virtual void funB()
{}
};
class C : public A, public B
{
public:
virtual void fun1()
{}
virtual void fun2()
{}
virtual void funC()
{}
};
int main()
{
C c;
return 0;
}
#include
using namespace std;
typedef void(*VFPTR) ();
class A
{
public:
virtual void fun1()
{}
};
class B
{
public:
virtual void fun2()
{}
};
class C : public A, public B
{
public:
virtual void fun1()
{}
virtual void fun2()
{}
virtual void fun3()
{}
};
void Print(VFPTR vTable[])
{
cout << "虚表地址:" << vTable << endl;
for (int i = 0; vTable[i] != nullptr; ++i)
{
printf("第%d个虚函数地址:0X%x, ->", i, vTable[i]);
vTable[i]();
}
cout << endl;
}
int main()
{
C c;
VFPTR* vTableA = (VFPTR*)(*(int*)&c);
Print(vTableA);
cout << endl;
VFPTR* vTableB = (VFPTR*)(*(int*)((char*)&c + sizeof(A)));
Print(vTableB);
return 0;
}