【翁恺】21-多态的实现

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

理心炼丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值