How virtuals work in c++
任何一个类如果有虚函数,这个类的对象就会比正常的大一点。
#include <iostream>
using namespace std;
class A{
public:
A():i(10){};
virtual void f(){
cout<<"A::f()---->i="<<i<<endl;
}
int i;
};
int main(){
A a;
a.f();
cout<<sizeof(a)<<endl;
int *p=(int*)&a;
cout << *p << endl; //
p++;
cout << *p <<endl; // 10
return 0;
}

class XYPos{...};//x,y point
class shape{
public:
Shape();
virtual ~Shape();
virtual void render();
void move(const XYPos&);
virtual void resize();
protected:
XYPos center;
};

上面红框表示我们的对象,内部上面那个框是什么呢?是一个指针- vptr。
vPtr----指针
所有virtual类的对象里面的最头上都会加上一个隐藏的指针---vPtr--指向一张表 vtable(里面是所有virtual函数的地址),vtable是这个类的不是这个类的对象的,所有的vPtr的值是一样的
验证:vtable是这个类的不是这个类的对象的,所有的vPtr的值是一样的
#include <iostream>
using namespace std;
class A{
public:
A():i(10){};
virtual void f(){
cout<<"A::f()---->i="<<i<<endl;
}
int i;
};
int main(){
A a, b;
int *p = (int*)&a;
int *q = (int*)&b;
int *x = (int*)*p; // *p 是指针的值
cout << x << endl; // 0x2f068 很小的值, vtable 第一项是什么, *p 是vtable 里的内容,x 是vtable里的第一个地址
cout << *p << endl << *q << endl;
return 0;
}
4785264
4785264
ellipse
class Ellipse:public Shape{
public:
Ellipse(float maj,float mint);
virtual void render();//will define own
protected:
float major_axis,minor_axis;
};

ellipse 有自己的vtable,该vtable 的结构和父类shape的vtable是一样的。但是里面的值是不一样的。没有写自己的resize。 dtor也没写,但是编译器给它制造了一个。析构函数不一样,rendor不一样,resize 沿用了。
怎么发生动态绑定的?
这样的对象可以被当作shape对象看待。当 p 所指的 render 时候,实际上是 p 所指的对象的第一个地址取出来,从该地址访问到了这张vtable ,从 vtable + 2 得到 那个render 的地址,调用那个地址上的render 函数。
这种实现很快,不用在运行时候知道对象的类型是什么,只是从vptr找到了那张vtable, 然后找到了这个东西。

circle
class Circls:public Ellipse{
public:
Circle(float radius);
virtual void render();
virtual void resize();
virtual void redius();
protected:
float area;
};

circle 依然是shape的结构,可以被当作shape来看待。
What happens if
Ellipse elly(20F,40F);
Circle circ(60F);
elly = circ; // 10 in 5 ?
Ellipse 的 对象比 Circle 的小。做了 elly = circ; 后,elly 里面的对象是 Ellipse 还是 Circle 呢?
-
area of "circ" is sliced off
- (only the part of "circ" that fits in "elly" gets copied)
-
Vtable from "circ" is ignored;the vatable in "elly" is the Ellipse vatable
elly.render(); //Ellipse::render()
what happens with pointers?
Ellipse* elly = new Ellipse(20F,40F);
Circle* circ = new Circle(60F);
elly = circ;
-
well,the orifinal Ellipse for "elly" is lost...
-
"elly" and "circ" point to the same Circle object!
elly->render(); //Circle::render()
virtuals and reference arguments
void func(Ellipse& elly){
elly.render();
}
Circle circ(60F);
func(circ);
- references act like pointers
- "Circle::render" is called
virtual destructors
-
make destructors virtual if they might be inherited
Shape *p = new Ellipse(100.0F,200.0F); ... delete p;如果构造函数是virtual,析构函数也需要是virtual(动态绑定),vptr到vtable,执行对象自己的析构函数, 否则出错
C++默认是静态绑定(为了效率),其他OOP语言都是动态绑定
-
want "Ellipse::~Ellipse()" to be called
- must declare "Shape::~Shape()" virtual
- it will call "Shape::~Shape()" automatically
-
if "Shape::~Shape()" is not virtual,only "Shape::~Shape()" will be invoked!(调用)
Overriding 覆盖
如果父类和子类的两个函数是 virtual,它们构成Overriding关系。
- overriding redefined the body of a virtual function
class Base{
public:
virtual void func();
}
class Derived:public Base{
public:
virtual void func();
//overrides Base::func()
}
calls up the chain 调用父类的函数
-
you can still call the overridden function:
void Derived::func(){ cout<<"in derived::func!"; Base::func();//call the base class } -
this is a common way to add new functionality
-
no need to copy the old stuff!
return types relaxation(current)
-
suppose D is publicly derived from B D继承于B
-
"D::f()" can return a subclass of the return type defined in "B::f()"
-
applies to pointer and reference types
- e.g. D&,D*
relaxation example
class Expr{
public:
virtual Expr* newExpr();
virtual Expr& clone();
virtual Expr self();
};
class BinaryExpr:public Expr{
public:
virtual BinaryExpr* newExpr(); //ok
virtual BinaryExpr& clone(); // ok
virtual BinaryExpr self(); //error
};
只有通过指针或者引用才能构成upcast,所以返回本身是不行的
overloading and virtuals
-
overloading adds multiple signature
class Base{ public: virtual void func(); virtual void func(int); }; -
if you override an overloaded function,you must override all of the variants!
- can't override just one
- if you don't override all,some will be hidden
只有c++存在 name hidden.

943

被折叠的 条评论
为什么被折叠?



