关于构造函数在面向对象的继承中与普通成员函数的区别
时间:2012-11-20
来源:互联网
最近终于开始新的工作了,老婆说因为11月对于白羊座而言运势不太旺,所以找了很久的工作,遇到很多很傻的公司,
anyway,all is well
回到正题,首先声明我也不知道我自己理解的对不对,只是记录下来,请高手来指点的,
今天在看代码的时候发现,子类如果不写构造函数,那么父类的构造函数会被默认调用,这个大家都知道,今天我惊奇的发现,new 子类的时候的参数,也会被传到父类的构造函数中去,如果是java之类的强类型语言,那么只会调用默认构造函数,无参的那个,
然后就和朋友聊起来这个了,我们争论,究竟是子类继承了父类的构造函数,一如普通的成员函数那样,还是,在内部,没有发现构造函数的时候,子类自动的调用了父类的构造函数,并把参数传递进去,可能有点拗口,但是我觉得这里面的区别还是很大的,
所以大家就开始各自证明自己是对的,
于是我开始找源码,发现,似乎构造函数在继承的时候,父类的构造函数会被zend_hash_update更新到子类的function_table里面去,但是普通成员方法就没有这一步,最后大家都会被function_add_ref(**zend_function function),这个应该是为新的函数指针复制一份静态变量(因为调用子类对象中继承自父类的方法和直接从父类对象调用该方法是不一样的)
最后附上的是php里面的源码,
这是方法继承的代码
这是关于构造函数的代码
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
{
zend_function *function, *new_function;
if (!ce->parent) {
return;
}
/* You cannot change create_object */
ce->create_object = ce->parent->create_object;
/* Inherit special functions if needed */
if (!ce->get_iterator) {
ce->get_iterator = ce->parent->get_iterator;
}
if (!ce->iterator_funcs.funcs) {
ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
}
if (!ce->__get) {
ce->__get = ce->parent->__get;
}
if (!ce->__set) {
ce->__set = ce->parent->__set;
}
if (!ce->__unset) {
ce->__unset = ce->parent->__unset;
}
if (!ce->__isset) {
ce->__isset = ce->parent->__isset;
}
if (!ce->__call) {
ce->__call = ce->parent->__call;
}
if (!ce->__callstatic) {
ce->__callstatic = ce->parent->__callstatic;
}
if (!ce->__tostring) {
ce->__tostring = ce->parent->__tostring;
}
if (!ce->clone) {
ce->clone = ce->parent->clone;
}
if(!ce->serialize) {
ce->serialize = ce->parent->serialize;
}
if(!ce->unserialize) {
ce->unserialize = ce->parent->unserialize;
}
if (!ce->destructor) {
ce->destructor = ce->parent->destructor;
}
if (ce->constructor) {
if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
ce->parent->name, ce->parent->constructor->common.function_name,
ce->name, ce->constructor->common.function_name
);
}
return;
}
if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) {
/* inherit parent's constructor */
zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function);
function_add_ref(new_function);
} else {
/* Don't inherit the old style constructor if we already have the new style constructor */
char *lc_class_name;
char *lc_parent_class_name;
lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
if (function->common.fn_flags & ZEND_ACC_CTOR) {
/* inherit parent's constructor */
zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function);
function_add_ref(new_function);
}
}
efree(lc_parent_class_name);
}
efree(lc_class_name);
}
ce->constructor = ce->parent->constructor;
}
/* }}} */
anyway,all is well
回到正题,首先声明我也不知道我自己理解的对不对,只是记录下来,请高手来指点的,
今天在看代码的时候发现,子类如果不写构造函数,那么父类的构造函数会被默认调用,这个大家都知道,今天我惊奇的发现,new 子类的时候的参数,也会被传到父类的构造函数中去,如果是java之类的强类型语言,那么只会调用默认构造函数,无参的那个,
然后就和朋友聊起来这个了,我们争论,究竟是子类继承了父类的构造函数,一如普通的成员函数那样,还是,在内部,没有发现构造函数的时候,子类自动的调用了父类的构造函数,并把参数传递进去,可能有点拗口,但是我觉得这里面的区别还是很大的,
所以大家就开始各自证明自己是对的,
于是我开始找源码,发现,似乎构造函数在继承的时候,父类的构造函数会被zend_hash_update更新到子类的function_table里面去,但是普通成员方法就没有这一步,最后大家都会被function_add_ref(**zend_function function),这个应该是为新的函数指针复制一份静态变量(因为调用子类对象中继承自父类的方法和直接从父类对象调用该方法是不一样的)
最后附上的是php里面的源码,
这是方法继承的代码
static void do_inherit_method(zend_function *function) /* {{{ */ { /* The class entry of the derived function intentionally remains the same * as that of the parent class. That allows us to know in which context * we're running, and handle private method calls properly. */ function_add_ref(function); } /* }}} */
这是关于构造函数的代码
static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
{
zend_function *function, *new_function;
if (!ce->parent) {
return;
}
/* You cannot change create_object */
ce->create_object = ce->parent->create_object;
/* Inherit special functions if needed */
if (!ce->get_iterator) {
ce->get_iterator = ce->parent->get_iterator;
}
if (!ce->iterator_funcs.funcs) {
ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
}
if (!ce->__get) {
ce->__get = ce->parent->__get;
}
if (!ce->__set) {
ce->__set = ce->parent->__set;
}
if (!ce->__unset) {
ce->__unset = ce->parent->__unset;
}
if (!ce->__isset) {
ce->__isset = ce->parent->__isset;
}
if (!ce->__call) {
ce->__call = ce->parent->__call;
}
if (!ce->__callstatic) {
ce->__callstatic = ce->parent->__callstatic;
}
if (!ce->__tostring) {
ce->__tostring = ce->parent->__tostring;
}
if (!ce->clone) {
ce->clone = ce->parent->clone;
}
if(!ce->serialize) {
ce->serialize = ce->parent->serialize;
}
if(!ce->unserialize) {
ce->unserialize = ce->parent->unserialize;
}
if (!ce->destructor) {
ce->destructor = ce->parent->destructor;
}
if (ce->constructor) {
if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
ce->parent->name, ce->parent->constructor->common.function_name,
ce->name, ce->constructor->common.function_name
);
}
return;
}
if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) {
/* inherit parent's constructor */
zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function);
function_add_ref(new_function);
} else {
/* Don't inherit the old style constructor if we already have the new style constructor */
char *lc_class_name;
char *lc_parent_class_name;
lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
if (function->common.fn_flags & ZEND_ACC_CTOR) {
/* inherit parent's constructor */
zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function);
function_add_ref(new_function);
}
}
efree(lc_parent_class_name);
}
efree(lc_class_name);
}
ce->constructor = ce->parent->constructor;
}
/* }}} */
作者: kylidboy 发布时间: 2012-11-20
看明白了,是来晒老婆的。元芳你觉得呢?
作者: hmly 发布时间: 2012-11-21
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28