2014년 8월 12일 화요일

[강좌#19]연산자 오버로딩(Overloading)[닷넷C#교육/ADO.NET강좌/ASP.NET교육잘하는곳/C#,ASP.NET교육추천/닷넷실무교육/.NET,C#/ADO.NET교육/닷넷학원/ASP.NET실무교육]

이번 강좌에서는 연산자 오버로딩에 대해 살펴 보겠습니다. 이전의 메소드 오버로딩과 비교해 보시구요... 잘 이해해 두시기 바랍니다. 

연산자 오버로딩 

연산자 오버로딩이란 +, >와 같은 표준 연산자들을 클래스의 용도에 맞게 작동토록 한 것이다. 연산자를 오버로딩 한다는 것은 이름은 같지만 받아 들이는 피연산자의 형식이 다른 연산자를 여러 개 정의 한다는 뜻이다. 연산자 오버로딩은 표준 연산자들이 가지는 단순 형식들에 대해 가지는 의미를 좀더 복잡한 형식에도 그데로 적용하고자 할 때 유용하게 쓰인다. 

다음과 같은 AddClass1 이 있다고 하자. 

public class AddClass1 { 
public int val; 


아래의 코드는 될 것 같지만 컴파일 되지 않는다. 

AddClass1 op1 = new AddClass(); 
op1.val=1 
AddClass1 op2 = new AddClass(); 
op2.val=2 
AddClass1 op3 = op1 + op2; //오류 +연산자가 AddClass1 형식의 피연산자에는 적용되지 않는 다는 점이다. 

위의 예제를 다음과 같이 고쳐 보자. 
using System; 

namespace OperatorOverload1 

public class AddClass1 

public int val; 
public static AddClass1 operator + (AddClass1 op1, AddClass1 op2) 

AddClass1 obj = new AddClass1(); 
obj.val = op1.val + op2.val; 
return obj; 




class Test 

static void Main() 

AddClass1 op1 = new AddClass1(); 
op1.val=1; 
AddClass1 op2 = new AddClass1(); 
op2.val=2; 
AddClass1 op3 = op1 + op2; 
Console.WriteLine("op1 + op2 = {0}", op3.val); 




결과는 다음과 같다. 


[조금 변형한 아래의 예제를 보자] 

using System; 

namespace OperatorOverload1 

public class AddClass2 

public int val; 

//아래의 함수는 AddClass1, AddClass2에서는 정의가 가능하며 AddClass3에서는 불가 
public static AddClass3 operator + (AddClass1 op1, AddClass2 op2) 

AddClass3 obj = new AddClass3(); 
obj.val = op1.val + op2.val; 
return obj; 




public class AddClass1 

public int val; 


public class AddClass3 

public int val; 



class Test 

static void Main() 

AddClass1 op1 = new AddClass1(); 
op1.val=1; 
AddClass2 op2 = new AddClass2(); 
op2.val=2; 
AddClass3 op3 = op1 + op2; 
Console.WriteLine("op1 + op2 = {0}", op3.val); 





다음은 C#에서 오버로딩 할 수 있는 연산자들이다. 

단항 연산자 : +, -, !, ~, ++, --, true, false 
이항 연산자 : +, -, *, /, %, &, |, ^, <><, >> 
비교 연산자 : ==, !=, <, ><=, >, >= 

-true와 false를 오버라이딩 하면 클래스들을 부울 표식 안에서 사용 할 수 있다. 
-+= 같은 배정 연산자는 오버로딩 할 수 없지만 +연산자를 오버로딩 함으로서 +=을 오버로딩 한 것과 같은 효과를 나타낸다. =의 경우 오버로딩 할 수 없는데 이 연산자는 작동 방식을 바꿀 필요가 없는 것이다. &&와 ||역시 오버로딩 할 수 없는데 이것 역시 &, |를 오버로딩 하면 된다. 
-< 와 >의 경우 반드시 쌍으로 오버로딩 해야 한다. 즉 < 를 오버로딩 했을 때 >도 반드시 오버로딩 오버로딩 해야 한다. 비교연산자를 오버로딩 할 때는 한 연산자에서 다른 연산자를 호출하는 식으로 구현해서 코드를 줄이곤 한다. 

public class AddClass1 { 
public int val; 

public static bool operator >= (AddClass1 op1, AddClass1 op2) { 
return (op1.val >= op2.val); 


public static bool operator < (AddClass1 op1, AddClass1 op2) { >
return !(op1 >= op2); 



-==와 != 연산자에 대해서는 위의 경우 처럼 사용이 가능하나 Object.Equals()와 Object.GetHashCode()도 재정의 하는 경우가 많이 있다. 즉 ==를 재정의 하는 부분에서 Equals 메소드도 재정의 함으로서 사용자가 == 또는 Equals() 어느 것으로 비교 하든지 같은 결과가 나타나게 할 수 있다. 

public class AddClass1 { 
public int val; 
public static bool operator == (AddClass1 op1, AddClass1 op2) { 
return (op1.val == op2.val); 

public static bool operator != (AddClass1 op1, AddClass1 op2) { 
return !(op1 == op2); 


public override bool Equals(object op1) { 
return val == ((AddClass1)op1).val; 


//GetHashCode 는 개체의 상태에 기반한 고유한 int 값을 얻는데 사용 한다. 
public override int GetHashCode() { 
return val; 





변환연산자 
산술연산자 뿐 아니라 형식들 사이의 암시적, 명시적 변환 방식도 오버로딩 할 수 있다. 서로 관련되지 않은 즉 상속 관계도 없고 공통의 인터페이스도 없는 형식들 사이의 변환을 지원 하려면 그러한 변환 연산자 오버로딩 이 필요 하다. 

-예를들어 ConvClass1과 ConvClass2 라는 두개의 클래스가 아무런 관계가 없다고 할 때 다음과 같은 암시적 변환은 불가능하다. 

ConvClass1 op1 = new ConvClass1(); 
ConvClass2 op2 = op1; 

물론 아래와 같은 명시적인 변환 역시 불가능하다. 

ConvClass1 op1 = new ConvClass1(); 
ConvClass2 op2 = (ConvClass2)op1; 

위의 두 가지 변환을 가능하게 할려면 다음 예처럼 변환방식을 코드로 정의 해 부어야 한다. 



public class ConvClass1 { 
public int val; 
//암시적 변환을 지정하는 키워드 : implicit 
public static implicit operator ConvClass2(ConvClass1 op1) { 
ConvClass2 retVal = new ConvClass2(); 
retVal.val = op1.val; 
return retVal; 



public class ConvClass2 { 
public double val; 
//명시적변환을 지정하는 키워드 : explicit 
public static explicit operator ConvClass1(ConvClass2 op1) { 
ConvClass1 retVal = new ConvClass1(); 
checked { 
//double을 int로 변환 
retVal.val = (int)op1.val; 

return retVal; 



ConvClass1은 int 값을 담으며, Convclass2는 하나의 double 값을 담는다. int 값은 double로 암시적으로 변환 될 수 있으므로 ConvClass1 에서 ConvClass2로의 변환을 암시적으로 정의 할 수 있다. 그 역은 가능하지 않으므로 반드시 명시적 변환으로 정의 해야 한다. 


[연산자 오버로딩 예제] 두 날짜의 차이를 구하기 위한 예문 
using System; 
public class Time 

private int Year = 0; 
private int DDay = 0; 
private int Month = 0; 

// 기본 생성자 
public Time() 

this.Year = 0; 
this.Month = 0; 
this.DDay = 0; 


//매개변수가 있는 경우의 생성자 
public Time(int Year, int Month, int DDay) 

this.Year = Year; 
this.Month = Month; 
this.DDay = DDay; 


// ‘-‘ 연산자 Overloading 
public static Time operator-(Time t1, Time t2) 

int newYear = t1.Year - t2.Year; //년도는 그냥 빼자 
int newMonth = 0; 
int newDDay = 0; 

//뒤의 월이 큰 경우 
if (t1.Month < t2.Month) >

newYear = newYear -1; //년을 1 빼고 
newMonth = newMonth + 12; //월을 12를 더 해줌, Carry(올림수) 


newMonth = newMonth + t1.Month - t2.Month; 

//뒤의 일이 큰 경우 
if (t1.DDay < t2.DDay) >

newMonth = newMonth -1; 
newDDay = newDDay + 30; 


newDDay = newDDay + t1.DDay - t2.DDay; 

Time newTime = new Time(newYear, newMonth, newDDay); 
return newTime; 


public override string ToString() 

return String.Format("{0}:{1}:{2}", Year, Month, DDay); 



public class OpOverloadTest 

public static void Main() 

Time t1 = new Time(2004, 05, 05); 
Time t2 = new Time(1977, 07, 07); 
Time t3 = t1 - t2; 

Console.WriteLine(t1); 
Console.WriteLine(t2); 
Console.WriteLine(t3); 

} 


평일주간[100%환급과정]
(8/18)Spring,MyBatis,Hibernate실무과정
(8/18)자바기초JDBC,Servlet/JSP까지
(8/18)PL/SQL,ORACLE HINT,TUNING
(8/25)C#4.0,WinForm,ADO.NET
(8/25)안드로이드개발자과정
(8/25)SQL기초에서 Schema Object까지
(8/25)오라클자바채용확정교육
평일야간[개인80%환급]
(8/21)Spring, MyBatis, Hibernate
(8/21)HTML5,CSS3,Ajax,jQuery마스터
(8/21)C#,Network,ADO.NET,ASP.NET
(8/26)SQL기초에서실무까지
(8/26)안드로이드개발자과정
(8/28)자바JSP,jQuery,Spring,MyBatis
주말주간[개인80%환급]
(8/16)C#,ASP.NET마스터(8/16)웹퍼블리싱 마스터
(8/16)Spring, MyBatis, Hibernate
(8/16)자바웹&스프링,마이바티스
(8/23)SQL기초에서실무까지
(8/23)자바,네트워크,웹&스프링
(8/30)안드로이드개발자과정
주말야간[개인80%환급]
(8/23)SQL기초에서실무까지
(8/23)자바,네트워크,웹&스프링

댓글 없음:

댓글 쓰기