类与对象
对象是类的实例化,当对象创建后,该对象的内存布局如何,不同的布局将影响对象的方法和属性的调用顺序。通过不同的调用顺序我们也能够看出各种语言背后的实现机制。
C++对象布局
静态语言C++中没有元类这一概念,对象创建后将继承该类的所有属性和方法。当涉及到虚函数的情况下,该类会产生一张虚表,用于决定调用的函数,继承情形下,编译器将修改虚表中函数地址。编译期间,编译器并不知道函数是来自基类或父类,只有在运行期间才知道具体的函数地址。一个类的虚表数量由基类的个数决定,子类的虚表将用于决定对象的调用顺序。
测试示例如下:
class A {
public:
virtual void f1()
virtual ~A()
};
class B {
public:
void f1()
virtual void f2()
~B()
};
class C:public A,public B{
public:
void f1()
virtual void f2()
~C()
};
intmain(void)
{
C c;
return 0;
}
类C(对象c)形成的虚表内存布局如下:
(gdb) p c
$1 ={ = , = {
_vptr.B = 0x40b640 },
类C的布局如下:
2. Python对象布局
Python为动态语言,对象可随时定义新的方法而不受类的限制。一个对象除继承类的方法外,自身还可以定义新的方法来覆盖原类方法;类和对象各有自身的元表用于保存各自的方法和属性,当对象出现自身元表查找失败后,就会查找类的元表来获取对应的属性和方法。
>>>class A:pass
...
>>>a = A()
>>>a.show = lambda x:print(x)
>>>a.show("hello,world")
hello,world
>>> a.__dict__
{'show': at 0x00000000003ECBF8>}
>>>A.__dict__
mappingproxy({'__weakref__':, '__dict__
':, '__doc__': None, '__module__':'__main
__'})
>>>A.s = lambda x:print("A:%s" % (x))
Traceback(most recent call last):
File "", line 1, in
TypeError:() takes 1 positional argument but 2 were given
>>>A.f = lambda self,x:print("A::f %s" % (x))
A::f 1
A:1
>>> A.f(a,1)//self参数本质上指向对应的对象
A::f1
这样对象a的布局图如下:
3. Lua对象布局
C++中类基于虚表来管理多重继承的函数,python中对象基于表的方式来管理类的函数和自身的函数,在Lua中我觉得管理的方式更加趋于继承的本质。Lua中无类的概念,类的实现采用函数来模拟。
一个类主要包含两部分:属性和方法,多重继承本质上用于确定属性和方法;对象创建时调用方法,OO语言则隐藏了this/self参数用于查找方法中的属性值。在lua中,表用于保存属性和方法,这样一个基本类就产生了。
Account ={
balance = 0,
withdraw = function(self,v)
self.balance = self.balance - v
end
}
functionAccount: deposit (v)
self.balance = self.balance
end
local mt=
functionAccount:new(o)
o = o or {}
setmetatable(o,mt)
return o
end
a =Account.new()
a:deposit(100)
print(a.balance)
元表采用lua中表结构形式,分号(Account:deposit)用于暗示该函数隐藏了self参数,a:deposit->getmetatable(a).__index.deposit(a,100)->Account.deposit(a,100)。封装、继承功能则通过修改查找元表函数实现。
function newAccount(balance1)
local self = {
balance = balance1
}
local withdraw = function(v)
self.balance = self.balance - v
end
local deposit = function(v)
self.balance = self.balance + v
end
local getBalance = function ()
return self.balance
end
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance
}
end
a =newAccount(0)
a.deposit(100)
print(a.getBalance())
闭包与类
从Lua的示例可以看出,Lua通过闭包来模拟类、对象。闭包的本质为一个环境,其主要为一个包含函数和变量的环境,类在一定程度上也是这种环境,如果对闭包中的函数定义加以访问限制,一个闭包就等价于一个类。
领取专属 10元无门槛券
私享最新 技术干货