C++回顾day03---<多态>

一:错误理解下的多态

#include <iostream>

using namespace std;

class Parent
{
public:
Parent()
{
cout << "Parent construct" << endl;
} void overrideFunc()
{
cout << "Parent override func" << endl;
}
}; class Child:public Parent  //1.有继承
{
public:
Child()
{
cout << "Child construct" << endl;
} void overrideFunc()  //2.有函数重写
{
cout << "Child override func" << endl;
}
}; void main()
{
Parent* p = new Child();  //3.父类指针指向子类对象
p->overrideFunc();      //4.进行多态调用
system("pause");
}

C++回顾day03---<多态>

这里是根据指针类型来判断调用那个函数执行(这是不对的)--->虽然也叫作多态

二:错误讨论 :使用函数来讨论到底出错在哪里?

(一)再次回顾对象的产生(重点)(对于一个含有无参构造方法的类的对象的生成)

class Test
{
public:
Test()
{
cout << "Test()" << endl;
} Test(int a)
{
cout << "Test(int a)" << endl;
} void getInfo()
{
cout << "use getinfo" << endl;
}
}; void main()
{
Test t; //会调用无参构造函数产生一个对象,若是不存在无参构造函数,则这里编译报错
Test t2(5); //会调用有参构造函数进行产生对象

t.getInfo();
t2.getInfo(); system("pause");
}

C++回顾day03---<多态>

重点:Test t3();是错误的!!!--->虽然声明不会报错,使用的时候会出错

C++回顾day03---<多态>C++回顾day03---<多态>

原因://warning C4930: “Test t3(void)”: 未调用原型函数(是否是有意用变量定义的?)
会认为该语句表示声明一个名为a的函数,返回类型是Test。

(二)详细错误案例指出《重点了解》

class Parent
{
public:
Parent()
{
cout << "Parent construct" << endl;
} void overrideFunc()
{
cout << "Parent override func" << endl;
}
}; class Child01:public Parent
{
public:
Child01()
{
cout << "Child01 construct" << endl;
} void overrideFunc()
{
cout << "Child01 override func" << endl;
}
}; class Child02 :public Parent
{
public:
Child02()
{
cout << "Child02 construct" << endl;
} void overrideFunc()
{
cout << "Child02 override func" << endl;
}
}; void testMulStatus(Parent* p) //想通过一个父类指针实现对子类对象方法的动态调用
{
p->overrideFunc(); //想实现对象方法的动态调用
}
void main()
{
Child01 c1;
Child02 c2;
testMulStatus(&c1);
testMulStatus(&c2); system("pause");
}
本意是通过同一个父类指针,实现对不同的子类的方法的调用

C++回顾day03---<多态>

三:真正的多态实现《重点》

(一)多态原则

1.要有继承
2.要有virtual函数重写
3.要有父类指针指向子类对象

(二)代码测试

class Parent
{
public:
Parent()
{
cout << "Parent construct" << endl;
} virtual void overrideFunc()
{
cout << "Parent override func" << endl;
}
}; class Child01:public Parent
{
public:
Child01()
{
cout << "Child01 construct" << endl;
} virtual void overrideFunc()
{
cout << "Child01 override func" << endl;
}
}; class Child02 :public Parent
{
public:
Child02()
{
cout << "Child02 construct" << endl;
} virtual void overrideFunc()
{
cout << "Child02 override func" << endl;
}
}; void testMulStatus(Parent* p) //想通过一个父类指针实现对子类对象方法的动态调用
{
p->overrideFunc(); //想实现对象方法的动态调用
} void main()
{
Child01 c1;
Child02 c2;
testMulStatus(&c1);
testMulStatus(&c2); system("pause");
}

C++回顾day03---<多态>

四:原理探析(虚函数表指针VPtr)

(一)多态中的虚函数表

当类中声明虚函数时,编译器就会在类中生成一个虚函数表
虚函数表是一个存储类成员虚函数指针的数据结构
虚函数表由编译器自动生成和维护
virtual成员函数会被编译器放入虚函数表中
存在虚函数时,每个类中都会有一个指向虚函数表的指针(vptr指针)
注意:虽然定义为虚函数,但是占用空间和原来成员函数大小是一样的,所以在内存上面唯一的区别在于多了一个虚函数指针(大小4字节)

(二)证明虚函数指针的存在

class Test
{
public:
int a;
int b;
public:
Test()
{ } void getInfo()
{
cout << "getInfo" << endl;
} void setInfo()
{
cout << "setInfo" << endl;
}
}; class Test02
{
public:
int a;
int b;
public:
Test02()
{ } virtual void getInfo()
{
cout << "getInfo" << endl;
} virtual void setInfo()
{
cout << "setInfo" << endl;
}
}; void main()
{
cout << sizeof(Test) << endl;
cout << sizeof(Test02) << endl; system("pause");
}

C++回顾day03---<多态>

无论是一个虚函数,还是两个或者多个虚函数,最终内存大小相差4字节。所以一个成员函数--->虚成员函数是不增加空间大小的。多的那4字节是由于虚函数表指针的增加导致的

(三)多态上虚函数调用步骤

每个对象会含有一个虚函数指针vptr,指向虚函数表,当父类指针调用重写虚函数时:首先会去找vptr,根据vptr去找对应的子类虚函数表,从而找到对应对象的方法进行调用

(四)虚函数和普通函数调用的区别

.若是普通成员函数,编译器可以直接确定被调用成员函数(静态编链)
.若是虚函数:编译器要根据对象的vptr指针,找到虚函数表,找到对应的虚函数进行调用(动态编链)
.所以虚函数的调用效率要低于普通成员函数,所以出于效率,没有必要全部定义为虚函数
上一篇:Matlab 如何绘制复杂曲线的包络线


下一篇:字符串aaaa......bbbb....ccc...dddddd用正则替换为abcd