부모클래스에 a()( 당연히 public 혹은 protected )라는 멤버 함수 있고 자식 클래스에서 a()라는 멤버 함수를 호출 하면 상속이
가능한것 처럼 operator 연산자 함수( 당연히 public 혹은protected )를 자식 클래스에서 호출하면 상속이 아닌가요?
일반적인 public 멤버라면 상속이 됩니다만 개체의 생성, 소멸, 복사에 관한 멤버는
특별한 의미를 갖기 때문에 각 클래스에서 책임지고 정의하게 되어 있습니다.
class B
{
public:
void f();
B& operator=(const B&);
};
class D : public B { };
D d1, d2;
d1.f(); // (1)
d1 = d2; // (2)
이때 (1)에서 호출하는 함수는 B::f()입니다. 상속받았으므로 당연한 얘기죠.
그러나 (2)에서는 그렇지 않습니다. D::operator=()가 호출됩니다. 이 함수는
컴파일러가 대신 만들어 주기 때문에 눈에 보이지 않을 뿐 B::operator=()와는
다른 함수입니다. 이것이 상속받은 멤버와의 차이입니다.
xCOperator.cpp: In constructor
`xCChildOperation<DataType>::xCChildOperation(int)':
xCOperator.cpp:78: class `xCChildOperation<DataType>' does not have any field
named `xCParentsOperation'
xCOperator.cpp: In constructor
`xCChildOperation<DataType>::xCChildOperation(int) [with DataType = int]':
xCOperator.cpp:98: instantiated from here
xCOperator.cpp:80: no matching function for call to `xCParentsOperation<int>::
xCParentsOperation()'
xCOperator.cpp:7: candidates are:
xCParentsOperation<int>::xCParentsOperation(const xCParentsOperation<int>&)
xCOperator.cpp:25:
xCParentsOperation<DataType>::xCParentsOperation(int) [with DataType = int]
xCOperator.cpp:98: instantiated from here
xCOperator.cpp:82: returning a value from a constructor
지금 이슈는 제가 진행하고 있는 스마트포인터를 이용한 프로젝트와 중요한 연관이 있기 때문에 테스트를 해 보았습니다.
상속도 잘 되고, 오버로딩도 잘 되는것 같은데 틀린 부분이 있으면 지적하여 주시기 바랍니다.
오버로딩
#include <iostream>
using namespace std;
class A {
public:
A& operator=(const A&) { cout << "A" << endl; }
};
class B : public A {
public:
B& operator=(const B&) { cout << "B" << endl; }
};
int main() {
A a, b;
a = b;
B c, d;
c = d;
return 0;
}
출력
A
B
상속
#include <iostream>
using namespace std;
class A {
public:
A& operator=(const A&) { cout << "A" << endl; }
};
class B : public A {};
int main() {
A a, b;
a = b;
B c, d;
c = d;
return 0;
}
13.5.3 Assignment
1. An assignment operator shall be implemented by
no n-static member function with exactly one
parameter. Because a copy assignment operator
operator= is implicitly declared for a class if not declared
by the user (12.8), a base class assignment operator is
always hidden by the copy assignment operator in
derived class.
2. Any assignemtn operator, even the copy assignment
operator, can be virtual. [Note: for a derived class D
with a base class B for which a virutal copy assignment
has been declared, the copy assignment operator in D
does not override B's virtual copy assignment operator.
부모 클래스의 대입 연산자는 항상 자식 클래스의 대입 연산자에
의해서 가려진다, 라고 명시되어 있군요 :) 버추얼 연산자라 해도
오버라이딩 되지는 않는다고 합니다.
감사합니다. 제가 알기로는 모든 연산자는 오버라이딩이 안된다는것으로 알고 있습니다. 일반 함수는 부모클래스에서 virtual void a(); 자식 클래서에서 virtual void a(): 할수 있지만 즉 재정의가 가능하지만 operator연산자는 재정의가 불가능한것으로 알고 있습니다.
위의 소수 경우는 재정의도 아니고 말 그대로 상속을 받아서 쓰는것인데...문법책에 보게 되면 생성자, 소멸자, friend, operator는 상속이 불가능하다고 나오는데...위의 소수 같은 경우는 현재 상속이
가능합니다. 그래서 마니 당황스럽습니다.
아니면 제 소스가 잘못된 경우인데!!!
170 라인의 a1 = a2 에서 호출하는 함수가 xCParentOperation::operator=라고
생각하시나 본데 그렇지 않습니다. 컴파일러가 만든 xCChildOperation::operator=를
호출합니다. (따라서 xCChildOperation의 경우 대입연산자를 명시적으로 정의하지
않으면 문제가 발생한다는 것을 눈치 채실 수 있겠지요? 복사생성자도요. 이외에도
군데군데 이상한 곳이 눈에 띄지만 지금 논의와는 관계가 없으니 언급하지 않겠습니다.)
17 ~xCParentsOperation( );
부모 클래스로 사용되는 클래스의 소멸자는 가상으로 선언하는 것이 보통입니다.
22 const xCParentsOperation< DataType >& operator= ( const xCParentsOperation< DataType >& Right );
보통 operator=의 반환형은 const가 아닙니다.
struct S;
int i, j, k;
(i = j) = k; // ok
S s1, s2, s3;
(s1 = s2) = s3; // error with const version
이렇게 쓸 일은 거의 없겠지만 내장형과 최대한 같은 식으로 동작하도록 하기 위해서입니다.
try-catch 구문
메모리 할당에 실패하면 생성자 내에서 예외를 받도록 되어 있는데 이것은 이상합니다.
m_Alloc은 초기화되지 않은 상태에서 m_Size만 초기화하고 생성이 완료되니까요.
제 말뜻은 생성자에서 throw bad_alloc() 같은 식으로 예외를 던지고 생성자를
호출하는 main 함수에서 예외를 받아 적절하게 처리하라는 뜻이었습니다.
지금은 자식 클래스에서도 new를 쓰니 operator=를 따로 정의할 필요가 있고
부모/자식 클래스 모두 복사생성자도 정의해야 하겠습니다.
코드:
class B
{
public:
void f();
B& operator=(const B&);
};
class D : public B { };
D d1, d2;
d1.f(); // (1)
d1 = d2; // (2)
이때 (1)에서 호출하는 함수는 B::f()입니다. 상속받았으므로 당연한 얘기죠.
그러나 (2)에서는 그렇지 않습니다. D::operator=()가 호출됩니다. 이 함수는
컴파일러가 대신 만들어 주기 때문에 눈에 보이지 않을 뿐 B::operator=()와는
다른 함수입니다. 이것이 상속받은 멤버와의 차이입니다.
제가 위에 올린 댓글에 대해서 설명을 좀 부탁합니다. 전 잘됩니다만.. 지금 제 플젝에서 좀 중요한 이슈라서 명확히 짚어야 하거든요
잠시 끼어들면, assignment operator에 의해 overwritten되는 object의 복사는 C++ 컴파일러가 멤버-wise constructor와 assignment operator를 생성을 합니다. (모든 경우에 그렇다는 것은 아니고, 클래스를 작성할 때, 별도의 지정이 없으면 그렇다는 이야기 입니다.)
그런데, 이렇게 컴파일러가 생성한 것은 경우에 따라 부적절할 수 있다는 것이 문제여서 주의를 기울어야 합니다.
또 한가지, 자바에서는 위의 경우 (컴파일러가 생성을 하는 경우)가 원천적으로 봉쇄가 되어 있기에 cloneable이나 clone 멤버를 만들게 되는데 이것을 생각해 보면 위의 답도 유추가 되리라 생각됩니다.(변환기를 만드신다고 하니 이해를 하시리라 생각합니다.)
----
I paint objects as I think them, not as I see them. atie's minipage
부모 클래스의 대입연산자가 public이라면 사용은 할 수 있지만 상속은
부모 클래스의 대입연산자가 public이라면 사용은 할 수 있지만 상속은 안됩니다.
생성자, 소멸자, 대입연산자, 프렌드는 상속되지 않습니다.
부모클래스에 a()( 당연히 public 혹은 protected )라는
부모클래스에 a()( 당연히 public 혹은 protected )라는 멤버 함수 있고 자식 클래스에서 a()라는 멤버 함수를 호출 하면 상속이
가능한것 처럼 operator 연산자 함수( 당연히 public 혹은protected )를 자식 클래스에서 호출하면 상속이 아닌가요?
일반적인 public 멤버라면 상속이 됩니다만 개체의 생성, 소멸, 복사
일반적인 public 멤버라면 상속이 됩니다만 개체의 생성, 소멸, 복사에 관한 멤버는
특별한 의미를 갖기 때문에 각 클래스에서 책임지고 정의하게 되어 있습니다.
이때 (1)에서 호출하는 함수는 B::f()입니다. 상속받았으므로 당연한 얘기죠.
그러나 (2)에서는 그렇지 않습니다. D::operator=()가 호출됩니다. 이 함수는
컴파일러가 대신 만들어 주기 때문에 눈에 보이지 않을 뿐 B::operator=()와는
다른 함수입니다. 이것이 상속받은 멤버와의 차이입니다.
일단 답변에 감사드립니다.그래서 제 나름대로 예제를 하나 만들어 보았
일단 답변에 감사드립니다.
그래서 제 나름대로 예제를 하나 만들어 보았습니다.
다음과 같은 오류가 납니다. 연산자 부분은 주석 처리를 했는데...
질문하신 내용과는 별로 관계가 없는 에러로군요.[code:1]te
질문하신 내용과는 별로 관계가 없는 에러로군요.
(1)에서 기초 클래스 부분을 초기화할 때는
xCParentsOperation<DataType>( Size )
으로 써야 합니다.
그리고 생성자는 반환값이 없으므로 (2)처럼 쓸 수는 없습니다.
생성자에서 뭔가 잘못되었으면 보통 예외를 던지는 식으로 처리합니다.
그렇군요...다시 수정했습니다.[code:1] 1 #incl
그렇군요...다시 수정했습니다.
디버깅을 해보게 되면 a1[ 0 ] = 1 함수에서 부모 클래스 operator 연산자 부분을 호출하게 됩니다. 이부분은 어떻게 되는건지요?
윽... 지금까지 operator[]를 말씀하신 것이었습니까? :?
윽... 지금까지 operator[]를 말씀하신 것이었습니까? :?
처음에 대입연산자(operator=)라고 하시길래 저는 계속 그쪽만 생각했네요.
operator[]는 당연히 상속됩니다.
처음에는 operator= 이것으로 질문 하였는데....operato
처음에는 operator= 이것으로 질문 하였는데....
operator 연산자는 아무거나 만들어도 상관 없다는 생각에
operator[] 연산자를 만들었습니다.
그러면 operator 연산자는 상속 가능한 연산자가 있고 상속이 가능하지 못한 연산자가 있는건가요?
operator=, 생성자, 소멸자, 프렌드만 상속이 안됩니다.위에서
operator=, 생성자, 소멸자, 프렌드만 상속이 안됩니다.
위에서 말씀드린 대로 그 의미가 특별하기 때문입니다.
지금 이슈는 제가 진행하고 있는 스마트포인터를 이용한 프로젝트와 중요한
지금 이슈는 제가 진행하고 있는 스마트포인터를 이용한 프로젝트와 중요한 연관이 있기 때문에 테스트를 해 보았습니다.
상속도 잘 되고, 오버로딩도 잘 되는것 같은데 틀린 부분이 있으면 지적하여 주시기 바랍니다.
오버로딩
출력
상속
출력
신기하게도 operator= 연산자도 상속이 가능합니다.[code:1
신기하게도 operator= 연산자도 상속이 가능합니다.
조금 수정 하였습니다.
operator= 연산자가 상속이 가능한 이유는 무엇인가요?
C++표준안에 다음과 같이 명시되어 있군요.[quote]13.5.
C++표준안에 다음과 같이 명시되어 있군요.
부모 클래스의 대입 연산자는 항상 자식 클래스의 대입 연산자에
의해서 가려진다, 라고 명시되어 있군요 :) 버추얼 연산자라 해도
오버라이딩 되지는 않는다고 합니다.
..
감사합니다. 제가 알기로는 모든 연산자는 오버라이딩이 안된다는것으로 알고
감사합니다. 제가 알기로는 모든 연산자는 오버라이딩이 안된다는것으로 알고 있습니다. 일반 함수는 부모클래스에서 virtual void a(); 자식 클래서에서 virtual void a(): 할수 있지만 즉 재정의가 가능하지만 operator연산자는 재정의가 불가능한것으로 알고 있습니다.
위의 소수 경우는 재정의도 아니고 말 그대로 상속을 받아서 쓰는것인데...문법책에 보게 되면 생성자, 소멸자, friend, operator는 상속이 불가능하다고 나오는데...위의 소수 같은 경우는 현재 상속이
가능합니다. 그래서 마니 당황스럽습니다.
아니면 제 소스가 잘못된 경우인데!!!
[quote="nayana"]제가 알기로는 모든 연산자는 오버라이딩이 안
그렇지 않습니다. 오버로딩이 허용되는 연산자 중에서 대입연산자를 제외한
모든 연산자는 오버라이딩이 가능합니다.
xCChildOperation::operator=을 명시적으로 선언하지 않았으므로 컴파일러가
대신 만들어 주는데 그 내용은 대략 다음과 같습니다.
170 라인의 a1 = a2 에서 호출하는 함수가 xCParentOperation::operator=라고
생각하시나 본데 그렇지 않습니다. 컴파일러가 만든 xCChildOperation::operator=를
호출합니다. (따라서 xCChildOperation의 경우 대입연산자를 명시적으로 정의하지
않으면 문제가 발생한다는 것을 눈치 채실 수 있겠지요? 복사생성자도요. 이외에도
군데군데 이상한 곳이 눈에 띄지만 지금 논의와는 관계가 없으니 언급하지 않겠습니다.)
답변에 감사드립니다. 님의 말씀대로면 디버깅을 해보면 부모클래스의 ope
답변에 감사드립니다. 님의 말씀대로면 디버깅을 해보면 부모클래스의 operator= 연산자를 호출하던데...이거는 무엇인지요?
그리고
군데군데 이상한 곳이 눈에 띄지만 지금 논의와는 관계가 없으니 언급하지 않겠습니다
이상한 부분은 어디인지요? 알려주시면 감사하겠습니다.
[quote="nayana"]님의 말씀대로면 디버깅을 해보면 부모클래스의
바로 위의 소스의 (1)로 표시한 곳에서 호출하는 것입니다.
17 ~xCParentsOperation( );
부모 클래스로 사용되는 클래스의 소멸자는 가상으로 선언하는 것이 보통입니다.
이렇게 쓸 일은 거의 없겠지만 내장형과 최대한 같은 식으로 동작하도록 하기 위해서입니다.22 const xCParentsOperation< DataType >& operator= ( const xCParentsOperation< DataType >& Right );
보통 operator=의 반환형은 const가 아닙니다.try-catch 구문
메모리 할당에 실패하면 생성자 내에서 예외를 받도록 되어 있는데 이것은 이상합니다. m_Alloc은 초기화되지 않은 상태에서 m_Size만 초기화하고 생성이 완료되니까요. 제 말뜻은 생성자에서 throw bad_alloc() 같은 식으로 예외를 던지고 생성자를 호출하는 main 함수에서 예외를 받아 적절하게 처리하라는 뜻이었습니다.지금은 자식 클래스에서도 new를 쓰니 operator=를 따로 정의할 필요가 있고
부모/자식 클래스 모두 복사생성자도 정의해야 하겠습니다.
[quote]코드: class B { public:
제가 위에 올린 댓글에 대해서 설명을 좀 부탁합니다. 전 잘됩니다만.. 지금 제 플젝에서 좀 중요한 이슈라서 명확히 짚어야 하거든요
잠시 끼어들면, assignment operator에 의해 overwri
잠시 끼어들면, assignment operator에 의해 overwritten되는 object의 복사는 C++ 컴파일러가 멤버-wise constructor와 assignment operator를 생성을 합니다. (모든 경우에 그렇다는 것은 아니고, 클래스를 작성할 때, 별도의 지정이 없으면 그렇다는 이야기 입니다.)
그런데, 이렇게 컴파일러가 생성한 것은 경우에 따라 부적절할 수 있다는 것이 문제여서 주의를 기울어야 합니다.
또 한가지, 자바에서는 위의 경우 (컴파일러가 생성을 하는 경우)가 원천적으로 봉쇄가 되어 있기에 cloneable이나 clone 멤버를 만들게 되는데 이것을 생각해 보면 위의 답도 유추가 되리라 생각됩니다.(변환기를 만드신다고 하니 이해를 하시리라 생각합니다.)
----
I paint objects as I think them, not as I see them.
atie's minipage
nayana님께 드린 답변으로 다 설명이 됐다고 생각합니다만.[cod
nayana님께 드린 답변으로 다 설명이 됐다고 생각합니다만.
B 클래스에 컴파일러가 만들어주는 코드를 추가하면 대략 다음처럼 됩니다.
따라서
B c, d;
c = d;
를 하게 되면 A::operator=가 바로 호출되는 것이 아니라, B::operator=가 호출되고
그 안에서 A::operator=가 호출되는 것이지요. 이제 실행 결과가 왜 그렇게 되는지
이해하셨으리라 믿습니다.
좋은 설명들 감사합니다.
좋은 설명들 감사합니다.
설명 감사합니다.
설명 감사합니다.
댓글 달기