• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎(chǔ)} {C++ 高級(jí)} {C#界面,C++核心算法} {設(shè)計(jì)模式} {C#基礎(chǔ)}

            c#運(yùn)算符重載和技巧 (equal()函數(shù)的實(shí)現(xiàn)使用)

            Overview

            Occasionally this question pops up in newsgroups and forums : Why does C# insist on operator overloads being static? The person raising the question also usually complains how this prevents him or her from implementing virtual overloaded operators.

            This article explains why operator overloads have to be static in C# (or any other MSIL compiler), and also shows how you can simulate virtual overloaded operators very easily. It's not a universe-shattering theory (nor a very original one for that matter) and uses a very simple pattern though it's this very simplicity that makes it interesting.

            So, why do they have to be static?

            In C#, GC'd objects are heap-allocated (the managed CLR heap, not the CRT heap) and thus GC'd objects are always used as references (into the CLR heap). You cannot have stack-based GC'd objects in C# and what this means that you never know when an object variable is null. So, you can imagine what happens if operator overloads were instance methods and you tried to use an operator on a null object! Traditional C++ (as opposed to the CLI version) never faced this problem because the operators were always applied on stack objects; and if at all pointers were used, since pointers followed their own set of operational behavior - you never face a situation where an overloaded op-overload method is invoked on an invalid object.

            Traditional C++ example

            See below some C++ code that uses virtual operator overloads :-

            class Base
            {
            public:
                Base(int x):x_value(x){}
                virtual bool operator ==(const Base& b)
                {
                    return x_value == b.x_value;
                }
            protected:
                int x_value;
            };
            
            class Derived : public Base
            {
            public:
                Derived(int x, int y): Base(x), y_value(y){}    
                virtual bool operator ==(const Base& b)
                {        
                    Derived* pD = (Derived*)&b;
                    return (pD->y_value == y_value) && (pD->x_value == x_value);
                }
            private:
                int y_value;
            };
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                Base* b1 = new Derived(2,11);
                Base* b2 = new Derived(2,11);
            
                cout << (*b1==*b2) << endl;
            
                return 0;
            }

            When (*b1==*b2) is evaluated the == operator overload for class Derived is invoked which can be easily verified by trying out different values for the Base constructors for b1 and b2 or by setting a breakpoint inside the operator overload.

            A port to C#

            Taking what we know of C# let's attempt a straight-forward port of the above example to C#.

            public class Base
            {
                int x;
            
                public Base( int x )
                {
                    this.x = x;
                }
            
                public static bool operator==( Base l, Base r )
                {
                    if( object.ReferenceEquals( l, r ) )
                        return true;
                    else if( object.ReferenceEquals( l, null ) || 
                             object.ReferenceEquals( r, null ) )
                        return false;
                        
                    return l.x == r.x;
                }
            
                public static bool operator!=( Base l, Base r )
                {
                    return !(l == r);
                }
            
                public int X { get { return x; } }
            }
            
            public class Derived : Base
            {
                int y;
            
                public Derived( int x, int y ) : base( x )
                {
                    this.y = y;
                }
            
                public static bool operator==( Derived l, Derived r )
                {
                    if( object.ReferenceEquals( l, r ) )
                        return true;
                    else if( object.ReferenceEquals( l, null ) || 
                             object.ReferenceEquals( r, null ) )
                        return false;
                    
                    return (l.y == r.y) && (l.X == r.X);
                }
            
                public static bool operator!=( Derived l, Derived r )
                {
                    return !(l == r);
                }
            
                public int Y { get { return y; } }
            }
            
            class Program
            {
                static void Main()
                {
                    Derived d1 = new Derived( 2, 11 );
                    Derived d2 = new Derived( 2, 11 );
            
                    Console.WriteLine( d1 == d2 );
                    Console.ReadLine();
                }
            }

            If we run the program as it is above everything will work like the C++ version, but if we introduce a slight change to the program things begin to deviate greatly.

            class Program
            {
                static void Main()
                {
                    Base d1 = new Derived( 2, 11 );
                    Base d2 = new Derived( 2, 12 );
            
                    Console.WriteLine( d1 == d2 );
                    Console.ReadLine();
                }
            }

            What's going on here? As simple debugging will show us the despite the objects being compared being instances of the Derived class the Base class == operator is being called. This is because C# (and thus, most other languages) figure out which == operator method to call based on the known (i.e. compile-time) type of the object on the left hand side of the operation.

            There are ways around this as you'll see below.

            Simulating operator polymorphism with C#

            Here, we see how to simulate this in C# :-

            class Base
            {
                protected int x_value = 0;    
            
                public Base(int x)
                {
                    x_value = x;
                }
            
                public static bool operator==(Base b1, Base b2)
                {
                    if( object.ReferenceEquals( b1, b2 ) )
                    {
                        return true;
                    }
                    else if( object.ReferenceEquals( b1, null ) || 
                             object.ReferenceEquals( b2, null ) )
                    {
                        return false;
                    }
                    
                    return b1.Equals(b2);            
                }
            
                public static bool operator !=(Base b1, Base b2)
                {
                    return !(b1 == b2);
                }
            
                public override bool Equals(object obj)
                {
                    if( obj == null )
                        return false;
                    
                    Base o = obj as Base;
                    
                    if( o != null )    
                        return x_value == o.x_value;
                    return false;
                }
            
            
                public override int GetHashCode()
                {
                    return x_value.GetHashCode();
                }
            }
            
            class Derived : Base
            {
                protected int y_value = 0;
                
            
                public Derived(int x, int y) : base(x)
                {
                    y_value = y;
                }
            
                public override bool Equals(object obj)
                {
                    if( !base.Equals( obj ) )
                      return false; 
                      
                    Derived o = obj as Derived;
                    
                    if( o == null )
                        return false;
                    
                    return y_value == o.y_value;
                }
            
                public override int GetHashCode()
                {
                    return x_value.GetHashCode() ^ y_value.GetHashCode() + x_value;
                }
            }
            
            class Program
            {
                static void Main(string[] args)
                {
                    Base b1 = new Derived(10, 12);
                    Base b2 = new Derived(10, 11);
                    
                    Console.WriteLine(b1 == b2);
            
                    b2 = null;
            
                    Console.WriteLine(b1 == b2);
            
                    Console.ReadKey(true);
                }
            }

            Rather than rely on the == operator overload to do all of the heavy lifting we push all of the work onto the virtual Equals method, from there we let polymorphism work its magic.

            Points to note

            • The operator overload has to be static, so we have virtual instance methods that implement the logic for us and we invoke these virtual methods from the static operators

            • In our example, the method Equals corresponds to == and Equals is a virtual method (inherited from System.Object)

            • Within the static overload we need to check for null (to avoid null-reference exceptions)

            • Within each derived class's corresponding operator-logic method (Equals in our case), we cast the System.Object argument to the type of the class (e.g. - In the Derived class we cast to Derived)

            • While Equals and == already exist in System.Object, we can implement similar methods for any operator in our class hierarchies. Say, we need to implement the ++ operator, we then add a PlusPlus (or Increment) virtual method to the root base class in our object hierarchy and in the ++ overload we invoke the Increment method on the passed-in object.

            • In our example, we check for null and return true or false depending on whether the objects are both null or not. But, if you are implementing an operator like ++ then you might want to check for null and throw an ArgumentNullException (to override the inappropriate NullReferenceException that'd otherwise get thrown).

            History

            • Apr 19, 2005 : Article first published
            • Apr 20, 2005 : Fixed a bug in Derived.Equals and also changed the GetHashCode implementations for Base and Derived (thanks to Jeffrey Sax for pointing this out)

            posted on 2006-03-14 12:35 夢(mèng)在天涯 閱讀(1975) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C#/.NET

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計(jì)

            • 隨筆 - 461
            • 文章 - 4
            • 評(píng)論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類(lèi)

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1804663
            • 排名 - 5

            最新評(píng)論

            閱讀排行榜

            久久久噜噜噜久久中文福利| 久久福利片| 久久99中文字幕久久| 精品久久久久久久久中文字幕| 亚洲精品国产成人99久久| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 成人国内精品久久久久一区| 久久精品男人影院| 久久久SS麻豆欧美国产日韩| 久久精品国产亚洲av水果派| 久久av高潮av无码av喷吹| 色婷婷综合久久久中文字幕| 狠狠狠色丁香婷婷综合久久五月 | 国内精品伊人久久久影院| 久久精品aⅴ无码中文字字幕不卡 久久精品aⅴ无码中文字字幕重口 | 91精品国产色综合久久| 欧美亚洲另类久久综合婷婷| 精品国际久久久久999波多野| 精品久久久久久久久久久久久久久 | 久久精品亚洲欧美日韩久久| 亚洲AV无码久久精品蜜桃| 国产精品成人99久久久久91gav| 东方aⅴ免费观看久久av| 国产成人久久777777| 久久综合噜噜激激的五月天| 婷婷久久综合九色综合绿巨人| 免费精品99久久国产综合精品| 亚洲午夜久久久影院伊人| 婷婷久久综合九色综合九七| 国产午夜精品久久久久九九| 久久久久久毛片免费播放| 国产69精品久久久久观看软件| 久久精品国产亚洲精品| 久久免费精品视频| 69国产成人综合久久精品| 久久综合香蕉国产蜜臀AV| 久久精品aⅴ无码中文字字幕不卡| 久久久久人妻一区精品| 色综合久久综精品| 中文字幕亚洲综合久久2| 国产成人综合久久精品尤物|