C++中基类和派生类虚函数访问权限是否合理?
admin 发表于 2010-08-28 | 来源:互联网 | 阅读:
class Base
{
public:
virtual void func(){cout<<"Base"<<endl;}
};
class Derived: Base
{
private:
virtual void func(){cout<<"Derived"<<endl;}
};
int main()
{
Base *b = new Derived();
b->func();
}
实际调用为Derived::func();
请问这种以基类指针访问权限为准的设计有什么好处,是否破坏了派生类的访问机制?

也就是强制你使用多态了。就是在编码阶段就得按照OO的来。
虚函数的权限不要设计为private
楼主去看看OOD方面的书吧。
这是OO设计的原则。派生类中继承自基类的函数,不能比基类中对应的那个函数具有更严格的访问级别。也就是说,如果func在基类中声明为public的,那么在派生类中也必须是public的。原因就是你说的那个问题。这一点在Java语言中是强制性的,如果写类似上面的代码则编译都不会通过。
study
既然设计成虚函数了,它就是用作接口的,如果把它弄成私有成员,还有什么意义?
派生类中继承自基类的函数,不能比基类中对应的那个函数具有更严格的访问级别这一点我也认可。但为什么C++中不强制这一点,换句话说,有什么特殊的意义。另外,虚函数在派生类private而基类public这种方式有没有什么比较典型的用法。
合理不合理得看应用场合的。脱离场合讨论是没有意义的。
class Animal{ public: Say(){ } protected: virtual void SayImp(){cout < <"animal say!" < <endl;} }; class cat: Animal{ protected: virtual void SayImp(){cout < <"miao miao" < <endl;} }; class dog: Animal{ protected: virtual void SayImp(){cout < <"wang wang" < <endl;} }; int main() { Animal*b = new cat(); Animal*c = new dog() b-> Say(); c-> Say()} ===================================================================这样的话 就可以把虚函数藏起来。呵呵
class Animal { public: Say(){ SayImp();} protected: virtual void SayImp(){cout < <"animal say!" < <endl;} }; class cat: Animal { protected: virtual void SayImp(){cout < <"miao miao" < <endl;} }; class dog: Animal { protected: virtual void SayImp(){cout < <"wang wang" < <endl;} }; int main() { Animal*b = new cat(); Animal*c = new dog() b-> Say(); c-> Say() } =================================================================== 这样的话 就可以把虚函数藏起来。呵呵=======================应该是这样的。
楼上的代码不是我说的这种模式。我意思是,基类的多态暴露了派生类隐藏的函数,这算不算是语言的一个缺陷,还是C++有意设计成这样的。
^_^,我觉得是 program to interface…
暴露了吗,,要是想隐藏的话,干脆不要写派生类的函数..写了就是想满足动态绑定的用法,,lz有点钻牛角尖了吧,,
^_^,我觉得是 program to interface… ============不好意思,,没看清楚题目…
访问权限就是个摆设。你真正要维护一个类需要照顾的远不止私有公有这类的问题,反过来private成员你打算访问一样能访问,设private单纯给调试和以后修改添麻烦。个人从来不用class关键字,只用struct 默认public
如果一个功能(一个函数)你只是想通过基类调用,那么就这样做
我觉得访问权限的这种设定对于OO来说是不合理的。不过这种不合理并非表现在 b->func(); 上。请注意虚函数的语义。当基类定义一个虚函数时,它意味着其派生类的同原型函数的实现可以被基类所调用(请注意,这是某种形式的“权限”,但不是OO中定义的访问权限,和它无关)。这一点,是在设计基类时就确定的,不管派生类怎样变化,都无法改变它。对于派生类而言,它只是改变Derived::func的访问权限(这是隶属于“封装”的特性),并没有破坏虚函数的语义(即并不改变基类所拥有的调用派生类实现的“权限”,也就是并没有破坏“多态”),也不影响b->func();的使用。事实上,对于上下文无关的C++而言,当你写下b->func();时,你并不能够也不需要知道b指向哪一个实际类型,甚至那个缩小了访问权限派生类可以在很多年后才被设计出来。所以,就虚函数(多态)和访问权限(封装)而言,两者各有所属,互不干涉,因而访问权限的设定对虚函数是无害的;反过来说,虚函数的语义对访问权限来说也是无害的。它的不合理性其实表现在对继承语义的破坏上。一般而言,继承意味着基类所有的,派生类也必须有(注意,这里的“继承”是指OO的继承,而非某种语言的继承机制)。当你能够写 b->func(); 但却不能写d->func();时(设d的类型为Derived*),这种语义就被破坏了。事实上,所有缩小访问权限的名字隐藏都是破坏继承语义的,而并非只是针对虚函数而已。因此,如果Java在这一点上有严格的限制(我对此不太了解,所以加了“如果”),那么Java是对的。另一方面,C++的继承机制采用这种设定也是可行的。因为,C++并不是一门纯OO语言,C++只是支持OO的编程风格而已(就象它也支持其他编程风格)。因此,如果标的是OO,那么该设定不对;如果标的是C++,则可行。C++给你更多的选择权利,代价则是你必须履行选择的义务,并且了解你的选择。举例来说,如果你用Java做OOD,那么你只要做就行了,语言将尽力保障你行走在OOD的道路上;而如果你用C++做OOD,你必须清楚自己是在做OOD,从而放弃某些东西(比如不要将Derived::func设计成私有)。付出了这些代价后,你所得到的好处是:你还可以选择不做OOD,或者你可以用非OO的东西来辅助OOD,取长补短,相得益彰。PS:楼主的代码有一个小错误,class Derived: C/C++ code
public
Base …以上所说的继承,均是指公有继承。其他类型的继承具有不同的语义,是要区别对待的。
学习学习!
很想问卫亭,你那个OO的定义是什么?貌似不存在OO的标准定义啊。
to Vitin感觉C++不限制的唯一原因就因为C++不是纯粹的OO语言,而JAVA,C#中都有限制。呵呵,这个理由很特别。
先mark
很想问卫亭,你那个OO的定义是什么? 貌似不存在OO的标准定义啊。OO就是面向对象(貌似废话)。面向对象是一个仍然发展着的概念,许多人都从不同角度来定义它,阐述它的内涵,或分析它的外延。从这一点来看,说“不存在OO的标准定义”,是对的。不过,这无碍于我们平时的交流和理解。当我们在说OO时,我们都知道我们说的是什么,这就够了。如果对OO还没有概念,可以参考以下定义:“面向对象是一种程序设计方法,或者说它是一种程序设计范型,其基本思想是使用对象,类,继承,封装,多态,消息等基本概念来进行程序设计。”这当然不是一个全面的、甚或精确的定义,毕竟OO仍然发展着。不过,以此为始(或者以你所能找到的某个OO定义为开始),不断地学习和实践,以及与别人交流,你就会逐步地加深对OO的理解,最终形成你个人的完整认识。taodm或许是对这句话有疑义:“这里的‘继承’是指OO的继承,而非某种语言的继承机制”,我解释一下:此处的OO即指一种方法或范型(可参考上述定义),它可以被一个特定语言所采纳,但又独立于语言之外。当语言采纳(或部分采纳)OO时,就会在语言中形成某个或某些机制,以实现OO中对应的概念或方法,从而令语言的使用者可以运用OO(如进行OOA、OOD、OOP等等)。语言中形成的机制,可以与OO中的对应概念完全一致,也可以有所区别。例如Java作为纯OO语言,其机制与OO就更贴近一些;而其他语言如C++,就可能有更多的差异存在。事实上,正是由于语言采纳并实现了OO,在不同程度上、不同范围中、不同环境下给予OO实践和检验的机会,并予以反馈,从而促进了OO的进步。总之,OO和语言中建立的OO机制都在不断发展的同时影响着对方,也受到对方的影响,两者既有区别又紧密联系。
很想问卫亭,你那个OO的定义是什么? 貌似不存在OO的标准定义啊。oo是本版的一位双性人
双星。。。
google "Robert C. Martin:面向对象设计的11原则–你称得上OO专家么?"另外,纯OO的语言python甚至根本就没有public/private控制
to Vitin 感觉C++不限制的唯一原因就因为C++不是纯粹的OO语言,而JAVA,C#中都有限制。 呵呵,这个理由很特别。呵呵,正是如此。如果将OO看成一种理念,那么JAVA、C#的理念是OO,而C++不是。C++的理念是通用和全面,这就与纯OO有冲突了。对C++而言,如果OO的内容没有与“通用和全面”相冲突,那么就采用它;如果有了冲突,就要改动它以避免之。总之,C++的立场和OO的立场是不同的;甚或JAVA和OO的立场也可以有所区别:它们现在相同只是因为现在JAVA是纯OO语言;哪天它不是了,它们就一定会产生不同。具体到现在说的这个特性,它在哪里妨碍了通用性了呢?或者说,C++采用这种设定,获得什么好处了呢?简而言之,就是 Chiyer 在16楼所言:“如果一个功能(一个函数)你只是想通过基类调用,那么就这样做”。举个例子。我们都知道上市公司需要出季报和年报。假设在我们设计的系统中,所有的上市公司都委托财务公司来完成年报。当然,财务公司要求一些接口获得相关数据。这没有问题。所有这些公司类型都继承自一个名为“上市公司”的基类(至于公司类型,当然上市公司有很多类型,如按行业分成:计算机、金融、房地产、石油等等等等),或者更确切的说,在我们的系统中基类是“由财务公司来完成年报的公司”。这个基类会定义一组虚函数给财务公司使用,而每个派生类(如“计算机上市公司”)来实现这些函数,并且这些实现函数也是公有的。这很好,因为对上市公司而言,这些函数返回的数据都可以是公开的(不管是以年报的形式还是以被其他人调用的形式)。对财务公司、对计算机上市公司的开发者,以及对其他调用者而言,这都是一个合理的解决方案。现在(比如说这套系统已经发布了几个版本以后),情况发生了一些变化:有某个类型的公司也想出年报了!(假设这个类型是“计算机非上市公司”,至于它为什么想出年报,不要问我:也许是某些老总突发奇想,也许是行业协会的新举措,也许只是谈判桌上的一个筹码,总之这是需求的事;作为开发者,我无能为力。)那么财务公司对此的要求是:提供与那些上市公司同样的接口。无疑,这是合理的,也是必须的。那么,理所当然地,“计算机非上市公司”将继承自“由财务公司来完成年报的公司”。但是,对计算机非上市公司的开发者而言,存在一个同样现实的问题:如果计算机非上市公司提供了这些接口,那么意味着这些开发着必须理解这些接口,并且,必须改变对该类型的看法(它现在是“由财务公司来完成年报的公司”了,如果你忘了这一点,那么新多出来的那些公有接口会时时地提醒你)。可能有人会说:“这很容易吧,不就是多几个接口吗?”是的,当只有几个接口时这确实不难;但是如果是几十个上百个呢?或者这样的改变将不止一次呢?计算机非上市公司的开发者会抱怨:“我明白有了新需求,我愿意实现那些接口,这对我并不难。但是,我并不想时时关注这些接口,也不想将这个类看作‘由财务公司来完成年报的公司’。我以前并不是这样看待它的,现在我仍然不希望这样做。因为,这对于财务公司之外的用户们毫无意义,我为此而花费的时间也得不偿失。”是的,你必须知道,一个公有函数和一个私有函数的意义是相差很大的。公有函数对开发者而言,意味着任何人都有可能调用它,责任重大啊!而私有函数则不同,它的用户是有限的,只是开发者自己,有时也包括一些friend,以及类似现在的财务公司那样不知情的调用者。同样的问题会出现在其他使用“计算机非上市公司”的用户那边,他们会问:“为什么有这些新的函数出现?它们对我有意义吗?是否暗示着什么,比如我要贴更多的钱进去?”(这样说的用户可能是公司的债主,或者股东——当然了,我们知道有些股份公司也是不上市的,如有限责任公司)OK,我们看到了,为一个类增加原本的设计中不存在的公有接口是需要代价的,这些代价可能并不显著(比如,无法用代码行或工作量来衡量),但它确实存在,也确实给开发者和设计者带来(往往是巨大的)冲击,低估这些影响将造成难于预料的后果:例如将原本使用OOD精打细造起来的类型体系彻底埋葬(“哦我的老天,原本毫无关系的两个类突然搅和在一起了,我能够信任这个设计吗?”)。所以,此时需要一个平衡的方法,既满足财务公司,又不对类的开发者和其他使用者造成巨大的损失!方法很简单,就是我们现在讨论的:公有继承,但私有化函数。它不是纯粹的OO手段,但它是最有效的。也许有人会说:“这没什么用吧?继承仍然存在,使用者仍然可以将其转换为基类指针再调用它。”是的,使用者确实可以这样做,如果他有需要的话。但是,访问控制本身(的主要目的)并不是为了拒绝使用者使用。而是,它让开发者和使用者达成的一个协议:“我提供一些公有函数给你,并且保证你使用它而毫无问题(例如,不破坏对象内部的状态);另外,还有一些私有函数,你不必了解它,也不必使用它。”请注意,两者的力度是不同的。作为使用者,你仍然可以想尽办法绕过它(最起码,如果你是黑客的话,你总能想到办法),但开发者不提供任何保证,你需要自己负责,仅此而已。所以,在本案例中使用访问控制,就减轻了开发者的负担(你无须承担所有人都可以访问的责任),也减少了使用者的困惑(你可以不用理会它们),而它对已有类型体系的冲击也是最少的(大体来说,这个类仍然和“由财务公司来完成年报的公司”没什么关系,只是借助继承机制来满足一个特定要求)。当所有人把这个继承看作技术手段而非语义上的改变时,这个方案就满足要求了:它已将为需求改变而付出的代价降到了最低。另一方面,很自然的,如果你是一个OO的绝对拥护者也不必沮丧,因为除此之外还有其他的OO方法也可以解决问题,如Decorator模式等等,只不过它们都不够简约,有把问题进一步复杂化的趋势。总之,C++足以支持多种方法(或者说,支持多种风格下的不同解决方案),它们各有所长,你所需要做的是谨慎选择。这个例子稍稍长了一点,但愿没有偏离主题。它只是一个例子,也不必过分看中,而C++并没有把自己打造成纯OO语言,其理由也不是一个例子就能完全解释的。事实上,OO的优势在于以一种强有力的联系架起了类型体系。而它的弱点也在于此:有时候,两个类之间的联系没有那么强,它们有联系,但不至于满足OO之“继承”的所有语义特点。特别是,在设计的一开始,可能无法正确预测或评估所有的联系。今后,总会有一些改变(而这些改变,如果仍然用纯OO方法来实行,将付出较大的代价)。鉴于这种情况,C++所做的是给予一些弹性。正如我们所知的,当一样东西有了弹性后,它就不那么“纯”了,但是它能够适应更多的情况,不是吗?
google "Robert C. Martin:面向对象设计的11原则–你称得上OO专家么?" 另外,纯OO的语言python甚至根本就没有public/private控制 无疑,与高手们(以及专家、大师们)交流,学习他们的观点和经验对于提升自己对OO的理解是很有好处的。比如,我之前说的“继承意味着基类所有的,派生类也必须有”。如果学过相关理论,你便会知道,这是指LSP(Liskov替换原则)。至于python,我不熟悉,提一下自己的认识:所谓“纯OO语言”,并非指它采纳OO的所有方面,而是指它不采纳OO之外的东西,特别是与OO存在冲突的东西。对于后者,语言必须做变通,它就不可能是纯OO了。至于采纳OO的所有方面,其实很难做到,因为OO仍然在发展中。如果因为新产生了一种技术就说原来的某个语言不再属于“纯OO语言”了,显然不合理。所以,如果python没有public/private控制,也没什么奇怪的。毕竟可以有其他“封装”的方法;甚或,python根本不涉及这一方面。呵呵,抱歉只能说到这个地步了,有哪位朋友熟悉python的,可以讲讲啊,让我也学习学习。
MARK!
我觉得这样做是有一定的应用范围的,例如鸵鸟是鸟,但是鸵鸟不会飞。
呵呵,为什么我得到的结论是:刻意的访问权限控制最多算2流特性,无足轻重呢。
up
学习
to Vitin 很精巧的设计,虽然跟继承的理念有点格格不入。很有代表性,感谢。
看看
困惑ing
动态多态性吧,指向基类的指针可以访问派生类的虚函数,在编译阶段不用考虑指针与对象不匹配的问题吧
合不合理,要看需求反正private肯定不合理有些代码虽然正确,但是不合理,里面有坏味道
UP
看着好奇,用g++编译了一下,没能编译通过:error: ‘Base’ is an inaccessible base of ‘Derived’
谈OO还是局限于语言来谈吧。访问权限是C++的重要OO特性,但不是最一般的OO特征。
留个名, 吃过饭上来学习!
那在基类中写成 protected可以了吧
网上很多人说python语言好,所以今天也花时间学习了一下,呵呵。当然了,象我这样毫无基础的,就从最简单地学起,一个 Python在线教程:http://www.cnsdn.com.cn/tools/Python/python给我的第一感觉是她很简单,学习她很愉快。当我看到一个特性时,我就会想到如果写python解释器,应该如何实现它。无疑,与C++相比,复杂度不在一个数量级上。——不要误会,这是对python的赞赏,而非相反。于是,在两三个小时后,我觉得自己不再是python小白了,甚至可以去CSDN的python版块闯荡一下了(呵呵,这当然只是玩笑。至少,目前我还没有写过一行代码,连入门也不算。只是一个稍有了解的外行罢了)。首先我了解到,python也支持面向过程。就这一点而言,似乎称其为“多范型语言”更贴切一些。不过,有那么多人称其为“纯OO语言”,总是有道理的吧。也许,他们想说的是“python语言的OO部分很纯”,比Java等更纯一些。不管怎么说,我无意在这个问题上纠缠,只要不产生语义上的误会就可以了,使用什么词汇表达是次要的。然后就一项项学习下来,表达式、控制流、函数、模块、数据结构……当然,最在意的还是它的类,它的OO部分。这样我就了解到,python的所有类成员都是公有的,除了数据成员可以用双下划线前缀来私有化(但愿我没有理解错误)。无疑,这是说类的所有函数必然是公有的。那么,大致可以得出结论:在python中,访问权限确实是一个次要的、边缘化的问题;并且,(我觉得)她这样做是非常正确的。请注意,当我这么说的时候,我是站在python的立场上说的。她所崇尚的是简单!访问权限对她而言,完全是鸡肋。就象,C所崇尚的是贴近机器,类对她而言也完全是鸡肋。所以,如果我以C++的立场,指责python不该不重视访问权限、指责C不该没有类,那我就是从门缝中看人,就是滑天下之大稽!那么反过来说呢?是否如 taodm 所言:“刻意的访问权限控制最多算2流特性,无足轻重”;或者如 iambic 所言:“谈OO还是局限于语言来谈吧。访问权限是C++的重要OO特性,但不是最一般的OO特征。”呢?我想,从某种角度而言,他们是对的。什么角度?taodm 可以从python(以及其他类似的语言)的角度来说,上面我说了,对python而言它肯定正确;甚至,相反的观点肯定错误。但是,(早料到我一定会说一个但书的吧,呵呵)…但是,对C++这么说,就不可能是正确的了。如果,…,我是说如果,将C++中的访问权限都去掉,会是怎样的情景呢?一个很显而易见的结果是:所有的对象都无法使用了!因为,你不知道它是否处于正确的(内部)状态!一个类,维护的是一个不变式(这同样是OO的一项主要内容之一)。你可以理解成,它的每个对象都一直满足一定的条件。比如我写一个类叫“正整数”,在内部用一个unsigned int的数据成员来存储具体的数值。那么我会肯定,这个数据成员不会为0,永远不会,因为它是正整数,我的类一定会保证这一点。但是,如果没有访问权限,我还能不能做这个保证呢?我还能不能毫无顾虑地拿这个类的一个对象做除数呢?无疑,我不能。当一项特性被去掉后整个语言就无法运做了,它能够被称为无足轻重吗?所以,对C++来说,这是错的。不过,再返回来说(颠来倒去的,很晕呢——自嘲一下,呵呵),这个理由也不能套在python上。明显的,python也不能应付这种情况,或许对正整数可以应付(毕竟还有私有数据成员),但是对更复杂的类、那些需要多个私有函数组合起来才能维护内部状态的类,她显然无能为力。但是(再一个但书),这不是python的错,当你企图用python来处理这种局面时,你早就已经错了。因为,python不是用来做这些的!用她处理复杂的类语义,与她崇尚简单的理念是南辕北辙、背道而驰的。python自己知道这一点,python的大部分使用者都知道这一点,而你(如果)不知道,那就是你的错了。现在我们知道,访问权限是C++的重要OO特性。那么,它是否不属于最一般的OO特性呢?这要看对“一般”的理解。如果它是指所有语言必须都支持的话,那么这样说是对的。但是,如果是指一个具有普遍意义的特性的话,这样说不不妥的。对于这个问题,我想说一个故事来解释一下(事先声明:我只是就事论事,并没有任何不良的企图。这个例子用了个不讨好的修辞手法名曰“夸张”,请别因此误会我哦,如果觉得不爽,骂我两句也好啊,或者就当是看我 Vitin 的一个笑话,别生气哦,小弟在这里先道个歉——貌似已经有些夸张了,我应该是过虑了吧,或者说有些过分了…不谈这些,先看故事吧):我们都知道,M国众议院有一个外交事务委员会(这个组织很……厄,打住,莫谈技术之外的事)。有一天,某人去国会山参观了(比如说,就是我)。逛了一圈以后,我发现了一个特别的现象:外交事务委员会的成员不多嘛,才几十个人,而整个众议院有几百个议员呢。外交事务委员会又没有准入限制,所有议员应该都可以参加的。所以,我立马去白宫找阿布反应情况了:“我说阿布啊,你们那个外交事务委员会不对劲啊!”“哦?怎么回事,你说说看。”“你看,众议院有几百号人,可外事委只有几十人,看来它并不受重视啊。恩,例如,你们的那位众议院议长先生(是政府的第三号人物,如果我没有记错的话)…哦不,这一届应该是议长女士,她也没有参加。很显然,外事委不具有代表性,国会对外交事务不重视!”我义愤填膺的说。“恩,…,你说的有道理。”阿布回答。 // 补充声明:这只是故事,纯属虚构,如有雷同,纯属…哦不,不会有雷同,将它看作平行世界里的一个笑话就好啦,我不负责哦“那么?”“我觉得,既然许多议员都没有参加,就说明它其实不重要。要知道,我虽然是总统,可掌控M国的其实是国会啦。所以…”“???”“所以,那个小赖在吗?…,对,小赖,是我阿布啊。我听 Vitin 反映了一个情况,觉得很有道理。所以,小赖啊,我看你就别做国务卿(政府第五号人物,相当于其他国家的外交部长)了,外交不重要嘛,你还是做我的国家安全顾问吧,将国务院交给副手吧。过两天我就把它给撤消算了。”“!!!”“哦,对了,Vitin,众议院的国家安全委员会有几个成员,是不是所有人都参加了?特别是我们的议长女士?”“……”我已经晕倒了…第二天,全世界都听说M国国务卿小赖女士下台了,奇怪的是,她甚至没有回任过去的国家安全顾问职务,于是人们对阿布和小赖的关系做出了总总猜测。几天以后,消息灵通的人终于打听到事情的真相(是谁透露的?据说是某个逛了国会山又去了白宫的人,嘿嘿),大家终于明白了,原来M国认为外交不属于一般的国家事务,所以把国务院给撤了。据内幕消息,这还和属于另一个党的议长女士有关。“会不会是…毕竟今年是大选年啊…”人们议论纷纷。后来,许多国家的外交部都撤了:“传说小国无外交,现在看来大国也一样啊,比如M国…”;再后来,LH国AL会将近期再度提交上来的扩大提案退了下去,秘书长大人对D国外交部长说:“哎,不是我不帮你,实在是我已经自身难保啦。看看人家M国,连小赖女士都下岗了,你我要早做打算啊。”…………………………好了,故事就到此为止了。再次声明,说这个故事只是为了阐述我的意见,没有其他任何意图哦。我觉得,如果国会是OO,议员是各种实现OO的语言,那么外交事务委员会就是访问权限了。它不必被所有语言所采纳,甚至不必被所有纯OO语言(专职议员,那些仅仅靠国会讨生活的人们)所采纳。但是,它确实是OO重要的组成部分。我们研究的对象既可以是每种语言中的访问权限(每个议员对外事的观点;当然,有些人,比如议长女士,对它不感兴趣,这很正常,甚至,这并不意味着议长女士也认为外事委应该撤消,只是她本人对此不参与而已),也可以是独立于语言之外,讨论一般意义上的OO的访问权限(整个国会外事委)。呵呵,这就是我对此的看法,大家不要拿砖头砸我哦,用水果皮就好啦…
说实话,还完全无法和你在“一般意义上的OO”这个概念本身上达成共识。不知道如何基于这个概念讨论“访问权限”
这是标准的没有把书看好!这种行为最可恶!!!
说实话,还完全无法和你在“一般意义上的OO”这个概念本身上达成共识。 不知道如何基于这个概念讨论“访问权限”这样,那么再举一个例子吧。贴近专业的,GP的例子:C/C++ code
// C++语言
class cpp
{
// …
};
// Java语言
class java
{
// …
};
// python语言
class python
{
// …
};
// 一般意义上的OO
template <typename 语言>
class 面向对象
{
public:
// …
class 访问权限
{
// … a lot of members depending on 语言
};
// …
};
// C++的OO
面向对象<cpp> c_oo;
// Java的OO
面向对象<java> j_oo;
// python的访问权限,需要特化
template <>
class 面向对象<python>::访问权限
{
// … just a few members for python
};
// python的OO
面向对象<python> py_oo;
如上所示,一般意义上的OO就是“template <typename 语言> class 面向对象”,它是独立于具体的语言之外的(和 class cpp、class python 等都无关)。它包含了普遍的、共性的东西。当然,具体到一个具体语言中OO时,如 面向对象<cpp> ,它的访问权限部分就(以及其他部分都)依赖于 class cpp 了。当然了,在这里C++采纳了访问权限的所有部分,因此“class 面向对象<cpp>::访问权限”不用特化,直接使用模版中的就行了;而对python而言,它只需要采纳访问权限的很小部分,因此需要一个特化版本,删除它所不需要的。请注意这两种区别:1、采纳一个特性的全部内容,但各语言之间有所差别,此时不需要特化,但是这个特性依赖于具体语言。此时,在上述“面向对象”模版中,模版参数“语言”类似一个traits,如 class cpp 和 class java 对于访问权限在某些方面是不同的,因此具体的“面向对象<cpp>::访问权限”和“面向对象<java>::访问权限”是不同的,但他们都从“template <typename 语言> class 面向对象<语言>::访问权限”实例化而来,都包含了它的所有部分和属于共性的子特性(如公有、私有的概念等等)。2、采纳一个特性的某些部分,此时需要对它做特化。如python,她特化的访问权限只包含一小部分内容。“面向对象<python>::访问权限”与“面向对象<cpp>::访问权限”相比,不仅依赖于不同语言,甚至连内容上也大不相同,前者简化了某些东西。此时,一个特化就很有必要了。这里使用GP的方式展示了他们的关系。需要注意的是:GP是一种反映客观世界的范型,但是它并没有反映客观世界的全部。这一点,对OO、PO等等来说也是一样的。因此,GP的展示只是一种模拟,是用来帮助理解的。它和现实一定是有差别的。这里用GP(而不是OO)是因为我觉得GP的方式在这个问题上与现实相差较小。如果用一个OO模型来展现这些关系,然后又发现这个模型和现实很又差距,请不要感到意外。请注意,所有的编程范型,都不是世界的全部,都是有适用范围的。否则,为什么我们一想到“鸟”就想到了“飞”,而鸵鸟偏偏不会飞呢?
MARK学习
Vitin的回贴总是很长,taodm的回贴总是很短。
看着好奇,用g++编译了一下,没能编译通过: error: ‘Base’ is an inaccessible base of ‘Derived’class Derived:public Base 加上红字的部分就可以了。
Vitin的回贴总是很长,taodm的回贴总是很短。我要学会长话短说,呵呵。
to Vitin 很精巧的设计,虽然跟继承的理念有点格格不入。 很有代表性,感谢。别客气,呵呵。
终于,又把GP扯出来了。何必要把访问权限一定要去耦合在某个编程范式上来讨论它呢。
这个问题也是OO的一大通病.很难控制子类型的规格.JDK里面,有些函数它不想实现,就往出抛异常.很丑陋.
这两位又就我们理解范围外的东西吵起来了哎~
终于,又把GP扯出来了。 何必要把访问权限一定要去耦合在某个编程范式上来讨论它呢。这个,不就是为了方便你理解嘛?
好吧,国会的例子太遥远,GP的例子太贴近,那么再举一个例子,我说得简短一些。比如我们每天都接触的,烹饪的例子。世界上有各种各样的菜系,中国的,外国的。单中国就分为八大菜系,还有很多小菜系。许多菜系间有一个共同点:它们都需要烹饪(如果觉得“烹饪”太中国化了,那么就是烧菜的方法,呵呵)。然后,烹饪中有很重要的一点:火候。比如大部分中国菜系都很关注火候,单单我们这些外行就知道文火、武火等等。其实对外国菜系也一样。假设现在有一个菜系(例如,法国菜;熟悉法国菜的人别骂我啊,我就一外行,借用一下它的名声而已),它不太注重火候,所有的菜都火力全开。那喜欢法国菜的人们觉得这样很好,事实上也确实很好,因为这对法国菜很合适。但是,这同样无法否定,火候对于其他菜系的重要性;以及,火候在烹饪中的重要地位。这个例子中,烹饪即指OO,菜系即指语言,火候即指访问权限。C++可以是某个中国菜系(或其他关注火候的菜系),python可以是法国菜系。烹饪是一种方法,是一种共通的东西。对一个厨师而言,他学习和掌握的往往只是某个具体的菜系。但是,他可以与别人交流烹饪,既可以交流他所在的菜系里的烹饪技术,也可以与其他菜系的厨师——如法国厨师——交流烹饪。当厨师们聚在一起说“烹饪”时,他们都知道自己在说什么,也明白别人在说什么。他们也可以在一起交流“火候”,即使法国厨师也没有任何不适,因为火候本来就是烹饪的重要组成部分,他不会因为自己用不到就认为烹饪中就不需要这些;甚至,他需要知道自己为什么不需要火候。同时,交流的内容既可以是具体的烧菜手法,也可以是烹饪的原则、通性之类形而上的东西。厨师们知道,烹饪,以及火候,一定是体现在具体的菜系、甚或菜肴,才能看得见的;但是,只有将同性和原理抽取出来、归纳为理论,再应用到实践中,才会有更大的意义。当中国厨师和法国厨师交流时,他们的共同语言即在于此。PS:貌似在篇幅方面,还有很大的改进空间;我要继续努力,呵呵。
强!!!我在高手中的争吵学到了东西!!对,不是争吵,是相互交流讨论.
这是虚函数表只认继承模式(class XX : public XXX),不认重写作用域吧
Vitin(卫亭)的人品真是让人佩服!
高手云集地,我到此一游
MARK
高手,学习了
学习
话说隐藏借口就是这样的吧,例如C#中:interface IA { void S(); }class AImp : IA { void IA.S() { } }这样AImp就具有IA的功能,但是不能直接AImp.S();需要(AImp as IA).S();