什么叫多态呢?
多态就是使用相同的调用方法,对不同的对象,会调用不同的类里面实现的函数。
1、
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
public:
void eating(void)
{
cout<<"use hand to eat"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
};
void test_eating(Human &h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_eating(h);
test_eating(e);
test_eating(c);
return 0;
}
2、
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
public:
virtual void eating(void)//
{
cout<<"use hand to eat"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
};
void test_eating(Human &h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_eating(h);
test_eating(e);
test_eating(c);
return 0;
}
3、
机制:
静态联编:非虚函数,在编译时确定好了调用哪一个
test_eating()就会调用Human中的eating()
动态联编:在运行时才会确定调用哪个函数
1、对象里有指针,指针指向一个虚函数表
2、当调用这个函数的时候,它首先找到虚函数表
然后调用里面的函数
4、
先将virtual去掉,打印对象的大小
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
void eating(void)
{
cout<<"use hand to eat"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
};
void test_eating(Human &h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_eating(h);
test_eating(e);
test_eating(c);
cout<<"sizeof(Human) "<<sizeof(h)<<endl;
cout<<"sizeof(Englishman) "<<sizeof(e)<<endl;
cout<<"sizeof(Chinese) "<<sizeof(c)<<endl;
return 0;
}
将virtual加上后:
原来是4,现在是16,比原来多了12字节,这12字节就是所谓的指针,它会指向一个虚函数表
5、
使用虚函数时需要注意的地方:
1)、多态只有在指针或者引用的情况下才会被用到,如果参数是传值的话,就无多态
将Human &h 改为--> Human h 传值
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
virtual void eating(void)
{
cout<<"use hand to eat"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
};
void test_eating(Human h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_eating(h);
test_eating(e);
test_eating(c);
cout<<"sizeof(Human) "<<sizeof(h)<<endl;
cout<<"sizeof(Englishman) "<<sizeof(e)<<endl;
cout<<"sizeof(Chinese) "<<sizeof(c)<<endl;
return 0;
}
传值的时候,例如在调用test_eating(e)的时候,e会变成human
2)、只有类的成员函数才能声明为虚函数
3)、静态成员函数不能是虚函数
4)、内联函数不能是虚函数
5)、构造函数不能是虚函数
6)、析构函数一般都声明为虚函数
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
virtual void eating(void)
{
cout<<"use hand to eat"<<endl;
}
~Human()
{
cout<<"~Human()"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
~Englishman()
{
cout<<"~Englishman()"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
~Chinese()
{
cout<<"~Chinese()"<<endl;
}
};
void test_eating(Human h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human* h = new Human;
Englishman* e = new Englishman;
Chinese* c = new Chinese;
Human *p[3] = {h, e, c};
int i;
for(i = 0; i < 3; i++)
{
p[i]->eating();
delete p[i];
}
return 0;
}
eating()被设置为虚函数,所以调用的时候分别都调用到了类里面实现的函数,
对于析构函数,调用的都是Human中的析构函数,显然是不应该这样的,每个对象在delete自己的时候,应该调用自己里面的清理函数,因此,应该将析构函数也设置为虚函数
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
virtual void eating(void)
{
cout<<"use hand to eat"<<endl;
}
virtual ~Human()//
{
cout<<"~Human()"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
virtual ~Englishman()//
{
cout<<"~Englishman()"<<endl;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
virtual ~Chinese()//
{
cout<<"~Chinese()"<<endl;
}
};
void test_eating(Human h)
{
h.eating();
}
int main(int argc, char **argv)
{
Human* h = new Human;
Englishman* e = new Englishman;
Chinese* c = new Chinese;
Human *p[3] = {h, e, c};
int i;
for(i = 0; i < 3; i++)
{
p[i]->eating();
delete p[i];
}
return 0;
}
这里需要注意一下:当去销毁一个派生类的对象的时候,先调用派生类里面的析构函数,然后调用基类的析构函数
7)、重载:函数参数不同,不可设为虚函数;覆盖:函数参数、返回值相同,可设为虚函数
8)、返回值例外:函数参数相同,但是返回值是当前对象的指针或引用时,也可以设为虚函数
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
virtual void eating(void)
{
cout<<"use hand to eat"<<endl;
}
virtual ~Human()
{
cout<<"~Human()"<<endl;
}
virtual void test(void)
{
cout<<"Human's test"<<endl;
}
};
class Englishman : public Human{
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
virtual ~Englishman()
{
cout<<"~Englishman()"<<endl;
}
virtual int test(void)
{
cout<<"Englishman's test"<<endl;
return 1;
}
};
class Chinese : public Human{
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
virtual ~Chinese()
{
cout<<"~Chinese()"<<endl;
}
virtual int test(void)
{
cout<<"Chinese's test"<<endl;
return 1;
}
};
void test_eating(Human &h)
{
h.eating();
}
void test_return(Human &h)
{
h.test();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_return(h);
test_return(e);
test_return(c);
return 0;
}
编译出错:将test()设置为虚函数,就意味着他们的名字、参数、返回值也一样。
但是有个例外:当返回值是类的指针或引用的时候,允许这么设置。
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Human{
private:
int a;
public:
virtual void eating(void)
{
cout<<"use hand to eat"<<endl;
}
virtual ~Human()
{
cout<<"~Human()"<<endl;
}
virtual Human* test(void)//
{
cout<<"Human's test"<<endl;
return this;//
}
};
class Englishman : public Human{//
public:
void eating()
{
cout<<"use knife to eat"<<endl;
}
virtual ~Englishman()
{
cout<<"~Englishman()"<<endl;
}
virtual Englishman* test(void)//
{
cout<<"Englishman's test"<<endl;
return this;//
}
};
class Chinese : public Human{//
public:
void eating()
{
cout<<"use chopsticks to eat"<<endl;
}
virtual ~Chinese()
{
cout<<"~Chinese()"<<endl;
}
virtual Chinese* test(void)//
{
cout<<"Chinese's test"<<endl;
return this;//
}
};
void test_eating(Human& h)
{
h.eating();
}
void test_return(Human& h)
{
h.test();
}
int main(int argc, char **argv)
{
Human h;
Englishman e;
Chinese c;
test_return(h);
test_return(e);
test_return(c);
return 0;
}