Chinaunix

标题: 关于perl 里类的实现的一些疑惑 [打印本页]

作者: xhaooo    时间: 2006-12-07 17:26
标题: 关于perl 里类的实现的一些疑惑
我一直对perl 里类的实现和使用有些迷糊, 书也看了, 但还是有些晕晕呼呼, 我觉得还是讨论来的快, 所以在此写一下关于我自己对perl类的理解, 希望大家能给于指点:
我的理解:
首先perl 的类就是一个包, 在这个包里定义的函数就是类的方法.
类整个的实现,是通过一个匿名hash引用实现的
通过hash 这种数据结构, 一个变量就可以映射一个复杂的数据结构, 这个变量也就是这个hash的引用.

my $self = {};
$self->{data1} = 1;
$self->{data2} = 2;
以上是数据的上, hash 对类的实现,
*问题1.  那么类的方法(包里函数)怎么实现的?
是hash 里面存了 子函数的引用? 然后就可以通过这个引用来调用函数,达到了类里对方法的调用的目的?

*问题2. 为什么类的方法的第一个参数都是类本身(那个引用变量)
因为这个类整个就是一个hash ,所以如果要操作类的数据(hash的数据), 就要通过hash的引用来访问,所以在类的方法体里, 需要一个这样的变量, 来对hash本身的数据,方法进行操作. 这样理解对不? :)


sub new {
    my $class = shift;
    my $self = {};
    bless $self,$class;
    return $self;
    }

*问题3. 每个类都会有个初始化函数new, 这new 是创造这个hash的地方. 但为啥也要先shift 一个class, 这个时候,那个承载类的hash应该还没有创建吧, 这个shift ,会得到什么? 还是根本就没用, 只是声明了个变量?

问题4. 哪位明白的高人,给解释一下bless, 是干啥的,  如果以上代码这样写
sub new {
    my $class = shift;
    my $self = {};
    $class = $class;
    return $self;
    }
效果是不是一样呢?

大概就这些困惑吧, 主要是对perl里类的实现机制没个清晰的把握, 希望已经明白的, 有经验的兄弟或姐妹能深入的谈一下, 自己的理解 , 谢谢了

希望讨论使大家对perl 的类有一个更清晰的理解, 能够对困惑, 迷糊朋友有所帮助!!
作者: flw    时间: 2006-12-07 17:57
问题1的回答:
hash 里面没有存它的方法,这完全是 -> 操作符的功劳。-> 操作符其实也没有什么神秘之处,它只不过是调用了一下它右边的那个 sub(注),并且把左边的那个引用变量 unshift 到 sub 的参数列表中去。注:为了正确地找到右边的那个 sub,它还需要把左边的那个引用变量 ref 一下取出原先 bless 进去的那个 tag

问题2的回答:
你理解的是正确的。

问题3的回答:
new 的第一个参数是 $class,不是 $self,也就是说,new 的第一个参数是类名称,而不是对象,你估计是自己把自己绕糊涂了,根本就不存在你所说的“那个承载类的hash应该还没有创建吧”的问题——你该不会连“类”和“类的实例”这两个概念都搞不清楚吧?

问题4的回答:
bless 的作用是给第一个参数(必须是个引用)打上一个印记(就好像盖个戳一样),而这个印记就标明了这个引用从此以后应该属于哪个类。理解了这个之后,你就明白 bless $self, $class 和 $class = $self 其实是完全不同的东西。bless $self, $class 之后,$class 还是原来的值,$self 也还是原来的值,只不过 $self 的印记变成了 $class 的内容。$class = $self 则是把 $class 变成和 $self 值相同的一个变量。

题外话:
1,new 的名称不是 Perl 语法的一部分,你完全可以叫 create, construct, build, 或者别的东西。
2,对象也不一定要用 hash 引用来存储数据,事实上任何类型的引用都可以,只不过 hash 引用正好方便表示 OOP 里面的“属性=>值”这种模型而已。事实上,CPAN 上就有一组用数组引用来构造类体系的,更加省空间。
3,Perl 对 OOP 提供的语法很有限,但是支持 OOP 的大多数概念。这些有限的语法包括 bless 函数、package 语句、-> 操作符、还有 @ISA 数组,以及 SUPER UNIVERSAL 等有限的几个关键字。除此以外我想再没有别的东西了。
作者: 兰花仙子    时间: 2006-12-07 23:10
不错的discuss哦,UP下.
作者: Namelessxp    时间: 2006-12-07 23:39
俺已经加收藏了,就等来人继续讨论了
作者: zenith518    时间: 2006-12-08 07:31
you can check perlboot carefully, you should get the point of why shift should be used!

Another document should give you the clear answer for the questions,
Perl Objects, References & Modules

In the perl module:
on class method, first you should get the calling object instance from implied first arguments,
this could be got by using the shift functions, then you could make calculation based on the object currently you calling.

BTW, Perl's the data_encapsulation is not so strict, so sometime for easy operation, you may directly modified the object's data from outside world, but from my point of view, this should be avoided.

in the end, the existing perl module can give you the most practical example/clue.
作者: 大司南    时间: 2006-12-08 10:17
好文,加深了对perl面向对象的理解.
作者: xhaooo    时间: 2006-12-08 17:06
标题: 谢谢 flw 兄的指点
关于指点1 我理解:
$object = new Class;
$object -> sub_a();

$object 就是这个类的对象 , sub_a() 时类的方法
"->" 把$object  unshift  到 sub_a() 的参数列表里,
所以在sub_a () 函数体里
sub_a(){
  my $self = shift ;
}
这个$self 这么样, 就是类的本身了
"->" 的功能原理真是神奇!

关于第3个问题:
"问题3的回答:
new 的第一个参数是 $class,不是 $self,也就是说,new 的第一个参数是类名称,而不是对象,...."
构造函数new 的第一个参数就是类的名字, 一个字符串.
用这个名字,通过bless 给那个hash 引用打上一个标签.
作者: flw    时间: 2006-12-08 17:46
> 这个$self 这么样, 就是类的本身了 "->" 的功能原理真是神奇!
你这里有点小错误,$self 在你举的这个例子中,是 $object,也就是对象/类实例而不是类。
作者: knuoxy    时间: 2007-03-08 14:52
通过你们的讨论我自己结合做了点总结,但有些地方用语言根本无法形容,哪位高手最好给例子?

类和方法理解
类其实就是一包,而包只不过是perl符号表中名字的集合,方法只不过是perl的一个子程序,
类名是第一参数,因为这个类整个就是一个hash,所以如果要操作类的数据,就要通过hash的引用
来访问,所以在类的方法体里,需要一个这样的变量,来对hash本身的数据,方法进行操作。
因此
   sub new{
    $class=shift  因为类名是第一参数 所以class就是类名?
     $this={}   通过这个引用来访问类的数据
bless $this  $this属于 $class类?

如何对hash类实现:
如$object=new Class;
$object->sub_a();
$object 此是是对象/实例,工作过程,hash本身没有存方法,这完全是->符号的功劳,它只不过是调

用了一下它右边的那个sub 并把左边的那个引用变量unshift到sub的参数列表中去,为了正确的找到
右边的那个sub,它还需要把左边的那个引用变量ref一下取出原先bless进去的那个。
因此在子程序 sub_a(){
   my $self=shift; 的时候$self就得到了引用变量$object 因此它成为对象/实例

类方法和实例方法

实例方法其主要

实例也就是之前的$this={}引用,而对象通过执行某种动作取其行为,因此实例方法也叫对象方法,而类方法则是针对于整个类??

[ 本帖最后由 knuoxy 于 2007-3-8 14:59 编辑 ]
作者: 福瑞哈哥    时间: 2007-03-08 15:11
一个hash引用被bless到某一个包中,Perl就完成了一个类的设计。
如果你写下$objref->submethod(@parms),(我猜想,至少你可以这样理解)Perl编译器就会把这个调用转化为如下的调用
$package::submethod($objref, @parms), 其中$package就是$objref被应用的包,
这样你就明白了吧,你在编写$package::submethod方法时,你可以使用$_[0]作为你要操作的对象了。
$package->submethod(@parms)调用被替换成
$package::submethod($package, @parms),
这样你在这个方法中就可以使用$_[0]得到$package了。

其他的都不过是对一个hash引用或者数组引用的操作而已。

很好理解啊。
作者: flw    时间: 2007-03-08 16:09
原帖由 knuoxy 于 2007-3-8 14:52 发表
通过你们的讨论我自己结合做了点总结,但有些地方用语言根本无法形容,哪位高手最好给例子?

类和方法理解
类其实就是一包,而包只不过是perl符号表中名字的集合,方法只不过是perl的一个子程序,
类名是第一 ...

拜托你把你想说的话和引用我的话分开好不好?
不然的话看上去都不知道在说什么。
作者: knuoxy    时间: 2007-03-08 16:44
Sub declareMain{
My $class=shift @_;
My($name,$extends,$implements)=@_;
Print “\n public class $name”;
}

$cup=new Cocoa;  #创建对象
$cup->declareMain(“Msg”,”java.appet.Applet”,”Runnable”);#因为$cup对象知道自己属于Cocoa类因此它调用的方式就如Cocoa::declareMain($cup(“Msg”,”java.appet.Applet”,”Runnable”);

Cocoa中
Sub declareMain{
My $class=shift @_;  将得$cup 因此$class知道自己也属于Cocoa类
不知道这么理解对不对。

另外 有点我非常模糊不清。
Sub new{
My $this={};
Print “\n/*\n**
Bless $this;
Return $this;
}

Sub declareMain{
My $class=shift @_;
My($name,$extends,$implements)=@_;
Print “\n public class $name”;
}

在这里因为第一个定义了类,而后创建了对象 在由对象调用子程序declareMain 那么是不是说declareMain就成为了实例方法,也就是虚方法 而sub new则是静方法 也就是类方法   

请高手在做解答。。

[ 本帖最后由 knuoxy 于 2007-3-8 16:47 编辑 ]
作者: knuoxy    时间: 2007-03-08 16:45
原帖由 flw 于 2007-3-8 16:09 发表

拜托你把你想说的话和引用我的话分开好不好?
不然的话看上去都不知道在说什么。



真不好意思。。我是直接ctrl+v的上去的。。

下次会注意
作者: flw    时间: 2007-03-08 17:31
看不懂你的程序。
My Sub 的。
而且不知道哪些是程序哪些是描述。
作者: perlpg    时间: 2007-03-08 17:33
标题: 其实有代表性的代码比文字更好解释。
package test1;
sub new{
    my $proto = shift;
    my $class = ref($proto) || $proto;

        my $self = {};
        bless $self, $class;
        return $self;
}

sub ShowME {
        return "Test1\n";
}

package test2;

sub oddness {
        my $class = 'test1';
        my $self = {};
        bless $self, $class;
        return $self;
}

sub createme {
        shift;
        my $self = {};
        $self->{CALLBACK} = shift || sub {print "In call test2\n"};
       
        return bless $self;
}

sub ShowME {
        my $self = shift;
        $self->{CALLBACK}();
        return "Test2\n";
}

package test3;

sub build {
        my $self = [];
        push @{$self}, sub {print shift,"\n"};
        bless $self;
        return $self;
}

sub ShowME{
        my $self = shift;
        print "Me store: @$self\n";
        $self->[0]('in test3 ShowME call.');
        return "Test3\n";
}

package main;

my $t1=test1->new();
print $t1->ShowME;

my $t20=test2->oddness;
print "I call package test2? ",$t20->ShowME;

my $t21=test2->createme;
# 注释/不注释下面一行看不同结果
#$t21->{CALLBACK} = sub {print "Call outside.\n";};
print $t21->ShowME;

my $t3=test3->build;
push @$t3,'+++';
$t3->[0]('in main call.');
print $t3->ShowME();

__END__

上面能说好大一篇了,其实知识就是这样‘试’出来的,想解释的都试试?
作者: flw    时间: 2007-03-08 17:33
> 将得$cup 因此$class知道自己也属于Cocoa类
不知道“将得”是啥意思。

> 那么是不是说declareMain就成为了实例方法,也就是虚方法
你到底是想说 declareMain 是实例方法还是想说它是虚方法?
作者: flw    时间: 2007-03-08 17:34
> #因为$cup对象知道自己属于Cocoa类因此它调用的方式就如Cocoa::declareMain($cup(“Msg”,”java.appet.Applet”,”Runnable”);
对象什么都不知道。它又没有智商你怎么让它知道?
作者: flw    时间: 2007-03-08 17:36
> 而sub new则是静方法 也就是类方法
这里又冒出一个“静方法”,你说的是指“静态(static)”的意思吗?怎么这么多我听都没听过的术语?
作者: flw    时间: 2007-03-08 17:37
原帖由 perlpg 于 2007-3-8 17:33 发表

其实有代表性的代码比文字更好解释。 ...

说的不错。以前讨论时我写过几段这样的代码,事实上文档里也有不少这样的代码。
作者: flw    时间: 2007-03-08 17:41
原帖由 knuoxy 于 2007-3-8 16:45 发表

真不好意思。。我是直接ctrl+v的上去的。。

复制就复制吧。你最起码可以在两边加个 【】 括号嘛。再要不这样子
----------------------------------
引用部分
----------------------------------
这样都很不错啊。

原帖由 knuoxy 于 2007-3-8 16:45 发表

下次会注意

下次复下次,下次何其多。
为什么不从这次就开始呢?
BBS 有编辑功能的。

总之一句话,如果你想要别人帮你,那就尽量方便一下看帖子的人。
不然人家都看不懂你在说什么,怎么帮你?
作者: alexru    时间: 2007-03-08 17:44
引用得注意“版权”的噢
作者: knuoxy    时间: 2007-03-08 18:30
我发觉flw说话很刻薄,可能你是无心之过。
论坛本来就是方便大家交流的。
我是凭借自己的感觉去发问的,难免有部分是表达不清,我想每个人都是这么走过来的(当然排除你在外)
但我给于你一些建议,你可以不必回答你觉的没有任何意义的帖子。但请您别
用嗤笑的语气回答问题。。

[ 本帖最后由 knuoxy 于 2007-3-8 18:32 编辑 ]
作者: flw    时间: 2007-03-08 19:33
原帖由 knuoxy 于 2007-3-8 18:30 发表
我发觉flw说话很刻薄,可能你是无心之过。
论坛本来就是方便大家交流的。
我是凭借自己的感觉去发问的,难免有部分是表达不清,我想每个人都是这么走过来的(当然排除你在外)
但我给于你一些建议,你可以不必回答你觉的没有任何意义的帖子。

> 可能你是无心之过。
我不是无心之过,我是故意的。

> 论坛本来就是方便大家交流的。
你觉得你给别人带来了“方便”了吗?让你编辑一下你的帖子你还不改,这是“方便交流”的态度吗?

> 我是凭借自己的感觉去发问的,难免有部分是表达不清。
这里不是你的博客,也不是你的日记本。“凭感觉去发问”,而不遵守最起码的规则,就应该受到批评。
你自己说话纠缠不清,我给你指出来,你不思考我的回帖倒也罢了,居然还好意思说“难免……”,你这治学态度就非常有问题。

> 你可以不必回答你觉的没有任何意义的帖子。
这里我是版主,我有权要求你。维持这里的秩序是我的义务,看到不符合版规,我就要规劝一下,对于部分拒不执行的,我可以采取强制措施。
作者: knuoxy    时间: 2007-03-08 19:56
呵呵。。。

我是来学习的。。。
作者: damofeixue    时间: 2007-03-15 15:53
何必呢,早承认错误。。。得了,呵呵




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2