C++/CLI에서의 연산자 오버로딩 패턴

  • Post author:
  • Post category:
  • Post comments:7 Comments
  • Post last modified:October 1, 2013

C++/CLI 템플릿 클래스에서 연산자 오버로딩 문제를 해결하는 간단한 방법을 소개할까 합니다. 아래 코드는 원문에서 베껴온 코드이고, 언급했다시피 결과는 이상하게도 **성공, 실패** 입니다.

// LibraryA.cpp : library file.
#include "stdafx.h"
#include <iostream>

using namespace System;

template<typename ABC>
public ref class ManagedClassA
{
public:
	int V;

	ManagedClassA(int v)
	{
		V = v;
	}

	static bool operator == (ManagedClassA^ a, ManagedClassA^ b)
	{
		// Return true if the fields match:
		return ( (a->V + b->V) % 2 == 0 );
	}

	static bool operator != (ManagedClassA^ a, ManagedClassA^ b)
	{
		return !(a == b);
	}
};

public ref class ManagedClassB : public ManagedClassA<int>
{
public:
	ManagedClassB(int v)
		: ManagedClassA(v)
	{
	}
};

// 단순 테스트용 클래스
public ref class Tester
{
public:
	static void Test1()
	{
		ManagedClassB^ b1 = gcnew ManagedClassB(1);
		ManagedClassB^ b2 = gcnew ManagedClassB(3);
		if(b1 == b2)
			System::Console::WriteLine("성공");
		else
			System::Console::WriteLine("실패");
	}
};


template<typename ABC>
public ref class ManagedClassC
{
public:
	int V;

	ManagedClassC(int v)
	{
		V = v;
	}

	static bool operator == (ManagedClassC^ a, ManagedClassC^ b)
	{
		// Return true if the fields match:
		return ( (a->V + b->V) % 2 == 0 );
	}

	static bool operator != (ManagedClassC^ a, ManagedClassC^ b)
	{
		return !(a == b);
	}
};

public ref class ManagedClassD : public ManagedClassC<int>
{
public:
	ManagedClassD(int v)
		: ManagedClassC(v)
	{
	}
};
// LibraryB.cpp : main project file.
#include "stdafx.h"

using namespace System;

void Test2()
{
	ManagedClassD^ b1 = gcnew ManagedClassD(1);
	ManagedClassD^ b2 = gcnew ManagedClassD(3);
	if(b1 == b2)
		System::Console::WriteLine("성공");
	else
		System::Console::WriteLine("실패");
}

int main(array<System::String ^> ^args)
{
	Tester::Test1();
	Test2();
    return 0;
}

아무래도 컴파일러 또는 링커 버그 같지만 확신은 못하겠군요. 어쨌거나 이 문제를 가볍게 회피하는 수단을 삽질 끝에 찾아냈습니다. 연산자 오버로딩을 이렇게 바꾸면 됩니다.

template<typename ABC>
public ref class ManagedClassC
{
public:
	int V;

	ManagedClassC(int v)
	{
		V = v;
	}

	virtual bool operator == (ManagedClassC^ b)
	{
		// Return true if the fields match:
		return ( (this->V + b->V) % 2 == 0 );
	}

	virtual bool operator == (ManagedClassC^ b)
	{
		return !(a == b);
	}
};

주의해 볼 곳은 `virtual` 키워드입니다. 재정의 가능한 메서드로 선언함으로써 컴파일러(또는 링커)가 지멋대로 메서드를 빼먹지 못하게 할 수 있는 것 같습니다. 참고로 연산자 == 는 맨처음 코드처럼 `static`으로 선언해도 되고, 위의 코드처럼 멤버 함수로 선언해도 됩니다. 만약 `static`으로 선언하고 싶다면 다음 코드처럼 고쳐야 합니다.

template<typename ABC>
public ref class ManagedClassC
{
public:
	int V;

	ManagedClassC(int v)
	{
		V = v;
	}

	static bool operator == (ManagedClassC^ a, ManagedClassC^ b)
	{
		// Return true if the fields match:
		return ( (a->V + b->V) % 2 == 0 );
	}

	static bool operator != (ManagedClassC^ a, ManagedClassC^ b)
	{
		return !(a == b);
	}

	virtual bool ReferenceEquals(ManagedClassC^ that)
	{
		return ManagedClassC::operator == (this, that);
	}

	virtual bool ReferenceNotEquals(ManagedClassC^ that)
	{
		return ManagedClassC::operator != (this, that);
	}

};
Author Details
Kubernetes, DevSecOps, AWS, 클라우드 보안, 클라우드 비용관리, SaaS 의 활용과 내재화 등 소프트웨어 개발 전반에 도움이 필요하다면 도움을 요청하세요. 지인이라면 가볍게 도와드리겠습니다. 전문적인 도움이 필요하다면 저의 현업에 방해가 되지 않는 선에서 협의가능합니다.
0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
시즈하
16 years ago

아, 맴버 함수로도 되는 거군요.
C++/CLI에 대해서 잘 몰라서 그건 생각 못했습니다 -o-;

저는 template을 generic으로 바꿔보니까 잘 되네요.
MS가 generic에서는 신경을 썼나봅니다…

최재훈
16 years ago

그냥 멤버 함수로 하면 안되고 가상 멤버 함수로 해야 되더라구요.

generic은 관리되는 타입에만 적용됩니다. 만약 네이티브 타입이면 generic으로 안 되고 template으로 구현해야 합니다. 그래서 이 모양이지요. 쩝.

방준영
16 years ago

안녕하세요. 이 문제는 컴파일러 버그가 아니고 템플릿을 소스 파일에 정의했기 때문에 생기는 문제입니다. 네이티브 템플릿처럼 헤더 파일에 두고 컴파일하면 잘될 겁니다.

그리고 소스를 보면 클래스 자체가 매니지드 ref class로 정의되어 있는데 위에서 시즈하님이 지적하신 것처럼 template 대신 generic을 쓰는 것도 좋은 해결책이죠.

최재훈
16 years ago

음…. 템플릿을 소스 파일에 정의했기 때문에 생기는 문제라는 점이 맞긴 하지만 동시에 틀리기도 합니다.

우선 이 글을 쓰고 나서 시간이 흘러 정확하게 기억나진 않지만 헤더 파일에 넣어도 같은 문제가 발생할 겁니다.

설사 헤더 파일에 연산자 정의를 넣어서 문제가 해결되더라도 또다른 문제가 있습니다. 이렇게 C++/CLI로 짠 클래스를 C#에서 가져다 쓰면, 어차피 헤더 파일에 정의된 코드를 적용할 방법이 없습니다. C#에서 C++ 헤더 파일을 include할 수도 없는 노릇이고……

그리고 generic의 타입은 반드시 관리되는 타입이어야 하기 때문에 네이티브 타입을 섞어쓰고자 할 때는 template을 쓰는 수밖에 없습니다.^^

illlust
illlust
14 years ago

템플릿 인스턴스화가 안되어서 그런 것 아닌가요..?
오래 된 글이군요..^^;;

illlust
illlust
14 years ago

헤더파일이 아닌 소스파일에 명시적으로
template ManagedClassA

;
template ManagedClassC

;
같은 식으로 인스턴스화 해주면 될 것 같네요…^^;;

최재훈
14 years ago

시간이 꽤 흘러 이제는 가물가물하지만 이미 시도해본 방법 같습니다. 한참 템플릿으로 장난칠 무렵이라 …