返回列表 回复 发帖

【讨论】编程

学c++语言需要学好c语言吗?还是只需要了解一点,
我个人认为不一定多精通,至少要学会c语言,才能学好c++语言,
请叫各位的意见呢?

Re:【讨论】编程

原则上是不要。但C++的书很少会从头开始,多少都假定你了解c。
C比较容易学,先学C也没什么不可。

不好意思的是我虽然都自学过,因为用得少,都不精通。
习惯了无聊,不无聊时才知道无聊是多么的不无聊。

Re:【讨论】编程

C和C++差别太大,可以直接学C++
C的编程思想无益于对C++的理解

Re:【讨论】编程

转贴一篇自己的文章,比较有趣。晶禧千年学了C++之后尝试做一做。
这曾经是一道贵宾认证试题(意思是答对了就能成为论坛贵宾啦。事实上这道题的讨论结果是产生了一篇精华、两个版主)

这次的题非常非常简单的啦,不过还是慷慨地给出了10分哦:)
要求:(不要你编程了,我都写好了,我是不是很好啊)
给出程式的输出结果,并用专业术语解释为什么会有这样的输出结果。 程式也是非常非常的简单:)


#include <iostream.h>

class boy//男人类
{
public://他敞开胸怀
    void LoveYou(float result)
    {
        cout << "Preety, I love you, marry me!" << endl;
    }
    void KissYou(float result)
    {
        cout << "Pretty, you are too sexy, I want to kiss you..." << endl;
    }
};

class girl : public boy//上帝说女人是……
{
public://她也敞开胸怀……我什么都没看见:)
    void LoveYou(int result)
    {
        cout << "I love you too...But I am too shy to say..." << endl;
    }
    void KissYou(float result)
    {
        cout << "You do what you want..." << endl;
    }
};

void main(void)
{
    girl  pretty;//一个女孩叫pretty
    boy  handsome;//一个男孩叫handsome

    girl  *the_pretty_home  = &pretty;//女孩说:我不要离开家……不嫁给你(真的?)!
    boy  *the_handsome_home = &pretty;//男孩说:来我家吧,我爱你!

////////////////////////////////////////
//----------?????他们在干什么呀?请写出结果-------------

    the_handsome_home->LoveYou(52.1f);
    the_pretty_home  ->LoveYou(52.1f);

    the_handsome_home->KissYou(52.1f);
    the_pretty_home  ->KissYou(52.1f);

////////////////////////////////////////
}

Re:【讨论】编程

[I]以下引用stuman的内容:
[/I]转贴一篇自己的文章,比较有趣。晶禧千年学了C++之后尝试做一做。
这曾经是一道贵宾认证试题(意思是答对了就能成为论坛贵宾啦。事实上这道题的讨论结果是产生了一篇精华、两个版主)

这次的题非常非常简单的啦,不......
偶永远成不了贵宾了,都不会。C忘光了。

Re:【讨论】编程

只能猜是:
Pretty, I love you, marry me!
I love you too...But I am too shy to say...
Pretty, you are too sexy, I want to kiss you...
You do what you want...

C++对我来说从来都一笔糊涂帐。我还真看不出来这个程序的妙处。有个地方把float对应到int大概有些不妥
习惯了无聊,不无聊时才知道无聊是多么的不无聊。

Re:【讨论】编程

[I]以下引用丸子的内容:
[/I]
偶永远成不了贵宾了,都不会。C忘光了。
倒。。。谁不知道你是软件高手
前几天我装了个redhat linux 8,正痛苦摸索中,呵呵

Re:【讨论】编程

[I]以下引用Thermo的内容:
[/I]只能猜是:
Pretty, I love you, marry me!
I love you too...But I am too shy to say...
Pretty, you are too sexy, I want to kiss you...
You do what you want...

C++对我来说从来都一笔糊涂帐。我还真看不出?.....
答案完全正确,呵呵,Thermo厉害啊

Re:【讨论】编程

这只是一个概念问题吧。girl的成员函数对boy的成员函数非常类似于重载(reload),但在概念上叫做“隐藏”(hide)。具体说,girl的LoveYou隐藏了boy的LoveYou,girl的KissYou隐藏了boy的KissYou,所以,对girl的派生类来说,boy的两个成员函数都是存在的。至于说参数为什么不一样,只是为了演示参数类型对“隐藏”的影响和与“重载”的重要区别:
girl和boy两个类中两个LoveYou()函数可能用“近似重载"来勉强解释,但是两个KissYou(float result)函数的形式一模一样,能用“重载”来解释吗?重载的函数必须参数不同的,对吧?重载也不可能发生在两个类中。
最让人迷惑的就是为什么the_pretty_home和the_handsome_home被赋予同样的地址(&pretty),按道理说the_pretty_home.LoveYou和the_handsome_home.LoveYou(还有两个KissYou)的结果应该完全一样,但竟然结果不同!那么更深层次的理解需要用类的内存构象来解释,涉及到编译器的处理,我想我们没必要探讨那么深入了。
这里,我们只要明白在隐藏的情况下,boy.LoveYou是能通过派生类girl调出来的。这在实践上可能没什么用处,不过在程序调试上万一出现这种错误,发现结果不对,百思不解,那么要当心这类问题了!

用调侃的解释来说:男孩娶了女孩以后,如果女孩管教不严,那么男孩可能会隐藏一些私房钱(好危险哦,小心他花心哦),这些私房钱是他自己的,但是没有上交给女孩,所以适当的时候他还是能花掉这些钱的。要彻底拿掉这些私房钱,女孩必须用强力手段“override”(覆盖)来镇压!

正确的输出结果是:

Preety, I love you, marry me!
I love you too...But I am too shy to say...
Pretty, you are too sexy, I want to kiss you...
You do what you want..

我祝福天下有情人终成眷属!

Re:【讨论】编程

ask:
对于C++来说,最强的功能是指针,最容易犯错的也是指针。本例中,关键是二个类的结构是完全相同的。这时候C++的编译器会根据最适合的方法来解释:

girl *the_pretty_home = &pretty;//女孩说:我不要离开家……不嫁给你(真的?)!
boy *the_handsome_home = &pretty;//男孩说:来我家吧,我爱你!

换句话说,这时,编译器并不知道the_handsome_home,the_pretty_home  到底是boy还是girl。必须根据具体的方法调用时才能确定。

。上例的结果实际上,严格来说并不准确,只能说对VC是正确的,对不同的编译器会有不同的处理方法,其结果也不同。

answer1:
我试过了,在C++Builder的编译器中,结果是一样的。

answer2:
我们需要更深层次来讨论这个问题,我反汇编了相关代码,这里是main()段:

:00401060 55                      push ebp
:00401061 8BEC                    mov ebp, esp
:00401063 83EC10                  sub esp, 00000010

:00401066 8D45FC                  lea eax, dword ptr [ebp-04]                    ;[ebp-04]为&pretty
:00401069 8945F8                  mov dword ptr [ebp-08], eax                  ;[ebp-08]为[the_pretty_home]
;girl  *the_pretty_home  = &pretty;

:0040106C 8D4DFC                  lea ecx, dword ptr [ebp-04]
:0040106F 894DF0                  mov dword ptr [ebp-10], ecx                  ;[ebp-10]为[the_handsome_home]
;boy  *the_handsome_home = &pretty;

:00401072 6866665042              push 42506666
:00401077 8B4DF0                  mov ecx, dword ptr [ebp-10]
:0040107A E890FFFFFF              call 0040100F
;the_handsome_home->LoveYou(52.1f);

:0040107F 6A34                    push 00000034
:00401081 8B4DF8                  mov ecx, dword ptr [ebp-08]
:00401084 E890FFFFFF              call 00401019
;the_pretty_home  ->LoveYou(52.1f);

:00401089 6866665042              push 42506666
:0040108E 8B4DF0                  mov ecx, dword ptr [ebp-10]
:00401091 E86FFFFFFF              call 00401005
;the_handsome_home->KissYou(52.1f);

:00401096 6866665042              push 42506666
:0040109B 8B4DF8                  mov ecx, dword ptr [ebp-08]
:0040109E E87BFFFFFF              call 0040101E
;the_pretty_home  ->KissYou(52.1f);

:004010A3 8BE5                    mov esp, ebp
:004010A5 5D                      pop ebp
:004010A6 C3                      ret

可以看到,the_pretty_home和the_handsome_home指针的数值的确是相同的,都指向了&pretty
但是为什么
the_handsome_home->LoveYou(52.1f);和
the_pretty_home->LoveYou(52.1f);
却得到了不同的结果。汇编代码提示出,在调用成员函数的时候已经被编译成不同的地址:一个是call 0040100F,一个是call 00401019。
经过函数跳转表后,call 0040100F是下面的代码:
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040100F(U)
|
:004010C0 55                      push ebp
:004010C1 8BEC                    mov ebp, esp
:004010C3 51                      push ecx
:004010C4 894DFC                  mov dword ptr [ebp-04], ecx
:004010C7 6814104000              push 00401014

* Possible StringData Ref from Data Obj ->"Preety, I love you, marry me!"
                                  |
:004010CC 6850BD4100              push 0041BD50
:004010D1 B9E0F44100              mov ecx, 0041F4E0
:004010D6 E875030000              call 00401450
:004010DB 8BC8                    mov ecx, eax
:004010DD E81EFFFFFF              call 00401000
:004010E2 8BE5                    mov esp, ebp
:004010E4 5D                      pop ebp
:004010E5 C20400                  ret 0004

非常明显,这就是boy类的成员函数LoveYou();而call 00401019同样可以证明是girl类的成员函数LoveYou();

最后我的结论是:上面的隐藏规则在编译的时候就确定和实现了,也即是“静态绑定”。C++类的指针不仅和它的值有关系,还和它的类别有关系。也就是说,编译器一定要知道the_handsome_home,the_pretty_home 到底是boy还是girl,才能确定具体的方法调用。这和C具有重大的区别。
返回列表