下面这段代码是这样的,ATM是主类,BankCard是基类,存款方法Deposit是非虚方法,取款方法Withdraw是虚方法,ForeignBankCard是派生类,用new和override分别重写这两个方法
card[1].Deposit(),调用了基类的方法,调用完之后,card[1]的money字段,为什么没有改?在调用card[1].Withdraw()方法的时候,money的初始值还是0,这是为什么,大侠们给讲一下内部原理吧!我才学C#两个星期,请尽量详细,谢谢了!namespace 银行卡
{
    class ATM
    {
        static void Main(string[] args)
        {
            BankCard[] cards = new BankCard[2];
            cards[0] = new BankCard();
            cards[1] = new ForeignBankCard();
            foreach (BankCard card in cards)
            {
                card.Deposit(5000);
                card.Withdraw(200);
            }
            ForeignBankCard a = new ForeignBankCard();
            a.Deposit(500);
            a.Withdraw(100);
            Console.ReadLine();
        }
    }    public class BankCard
    {
        private decimal money;        public BankCard()
        {
            money = 0m;
        }
        public void Deposit(decimal d)
        {
            money += d;
            Display(d, money);
        }
        public virtual void Withdraw(decimal d)
        {
            money -= d;
            Display(d, money);
        }
        public void Display(decimal a,decimal b)
        {
            Console.WriteLine("{0}卡存{1}元,当前余额{2}元", this.GetType().ToString(),a, b);
        }
    }    public class ForeignBankCard:BankCard
    {
        private decimal money = 0m;
        decimal rate = 0.01m;
        public ForeignBankCard()
        {
        }
        public new void Deposit(decimal d)
        {
            this.money = money + d;
            Display(d, money);
        }
        public override void Withdraw(decimal d)
        {
            d *= (1 + rate);
            this.money -= d;
            Display(-d, money);
        }
    }
}

解决方案 »

  1.   

    我把ATM里的下面这段代码            foreach (BankCard card in cards) 
                { 
                    card.Deposit(5000); 
                    card.Withdraw(200); 
                } 改成这样        foreach (BankCard card in cards)
            {
                if (card is ForeignBankCard)
                {
                    ForeignBankCard fCard = (ForeignBankCard)card;
                    fCard.Deposit(5000);
                    fCard.Withdraw(200);
                }
                else
                {
                    card.Deposit(5000);
                    card.Withdraw(200);
                }
            }
    运行成功,大至上可以明白问题所在。因为cards[1]的类型是BankCard,所以引用的是BankCard的Deposit而不是ForeignBankCard的Deposit,所以才会导致money的丢失。new关键字可以在派生类中隐藏基类的方法,但是,cards[1]的类型是基类BankCard,所以没办法起到隐藏作用,大至应该是这样。在某种说法上来说使用new是无奈之举,即是在作类升级时无法改动基类但又必须在派生类里重写某个方法时才用到的,一般正常情况下最好用虚方法来代替可能需要重写的方法。
      

  2.   

    card[1]调用的Deposit()是基类的,所以基类的money为5000而子类的仍然是0(子类初始化后money为0,而Desposit修改的是父类的money),而调用的Withdraw却是子类重载的方法。假如你把父类的Deposit()改为虚方法,并在子类中重载那么结果就又不一样了。new的话,就是子类的方法将父类方法隐藏,当子类的对象调用Deposit()时,就不会调用父类的Deposit()方法
      

  3.   

    我大概也明白你说的,但我不理解,card[1]是一个引用,并没有new出来一个基类的实体,怎么就给基类的money赋值了呢?能在内存层次上给解释一下吗?
      

  4.   


    这类new语法是c#(也是.net整个框架)这锅粥中的一粒老鼠屎,如果有人在跟我协作的工程使用它,我会觉得很恶心。
      

  5.   

    当看到有人写了new,我会严厉谴责他:难道你就那么缺乏创意,就不会给这个新的方法起个新的名字?一定要故意混淆重写的可继承方法?
      

  6.   


    也不能这么说,new本身只是一个应急措施,就象大楼的安全通道一样。没事从二十楼走安全通道到一楼着实恶心,但在电梯不能用的情况下,安全通道还是非常必要的。
      

  7.   

    应什么急?本来好好的继承通道,你需要应什么急?不好胡乱打比喻吧!当你写new的时候,自己明明知道这是与继承发生严重冲突的,所以根本不存在什么应急,而是主管故意。如果说这样写算作应急,那么为什么不真正应急去写个新的名字呢?到底应什么急?
      

  8.   

    你为什么要特意写上new?如果用安全通道做比喻,那么就相当于一个人私自把安全通道改为自家的粪池子,使人一旦闯入就掉入粪池子。而外边看上去还是安全通道似地引诱人上当。
      

  9.   

    BankCard card = new ForeignBankCard();其实是这样处理的,先初始化子类的构造函数,然后会初始化基类的构造函数,你在调试时,打个断点就明白它是如何工作的了。所以内存中会有两个对象。
      

  10.   

    在你的实例代码中,到底应什么急使得那么想在ForeignBankCard的Deposit呢?如果去理解业务概念,怎么也看不出来这里有什么应急。当ForeignBankCard从BankCard继承,Deposit方法需要重写,这不是已经清晰地表明“重写”概念了吗。这里看除非你就是想出点错,否则不会想到要写上new的。
      

  11.   

    应什么急使得那么想在ForeignBankCard的Deposit呢 -->  应什么急使得那么想在ForeignBankCard不再Deposit呢正常地在ForeignBankCard重写Deposit,就已经是重写了。其它的写法还算应急?应该算是从c++中继承的莫名其妙的糟粕吧。
      

  12.   

    sp1234说的是,但不是什么情况下都可以随意方法重命名的。某种情况下吧,比如,某派生类中的某个方法是继承基类的,但是,在作后续升级时,这个方法已经不适合使用基类,但是,派生类又在使用中或是重命名的代价太大,无法对该方法进行命名操作。那就只能用new方法重写了。有时作共享软件之类的,作后续升级,遇到这种bt问题的几率也不会是很低才是。
      

  13.   

    这个有商榷,cards[1]是ForeignBankCard类型的,只不过在子类中没有找到override的Despoist方法,就去父类中找有没有匹配的Despoist方法,如果没有就会到Objedt这个父类中找是否有Desposit方法。
      

  14.   


    嗯,大至上是如此,我对BankCard foreignBankCard = new ForeignBankCard(); 这种方式的声明不太会描述才会这么说的。
      

  15.   

    像楼主这种情况,一般是要抽象出接口来的,拉出个接口什么事情都解决了
    new 也不是没用处,当你继承一个框架内置的类时,某些方法需要重写就用得着了
    特别是GUI类库中,很多方法需要用NEW重写
      

  16.   

    从业务逻辑上来说,应该重写Deposit(),
    而不应该new
      

  17.   

    看下MSDN 对你问题的解释http://msdn.microsoft.com/zh-cn/library/ms173153.aspxoverride 是调用子类的,没问题,你上已经出来了而new话,就只看当前 声明的对象是什么类型就调用谁,而不是 对象实例