C++ 할당 연산자 오버로드된 함수를 상속할 수 없는 이유

제목 질문은 할당 연산자인 Operator=()가 가상 함수를 사용할 수 없는 이유일 수도 있습니다.

더 나은 내용을 설명하는 기사가 있습니다. 여기 링크: C++ 할당 연산자 오버로드 함수를 상속할 수 없는 이유는 무엇입니까? , 추측 과정은 다음과 같습니다.

class A1
{
public:
        int operator=(int a)
        {
                return 8;
        }

        int operator+(int a)
        {
                return 9;
        }
};

class B1 : public A1
{
public:
        int operator-(int a)
        {
                return 7;
        }
};

int main()
{        
        B1 v;
        cout << (v + 2) << endl; // OK, print 9
        cout << (v - 2) << endl; // OK, print 7
        cout << (v = 2) << endl; // Error, see below

        return 0;
}

VC 컴파일러 오류 메시지:

error C2679: 이진 '=': 'const int' 유형의 오른쪽 피연산자를 사용하는 연산자가 정의되지 않았습니다(또는 허용되는 변환이 없습니다).

분명히 정의를 찾을 수 없지만 이 코드의 의도는 파생 클래스 객체가 기본 클래스에서 상속된 할당 연산자를 사용하여 정수를 반환하도록 하는 것임이 분명합니다. 하지만 const int 연산자=(const int) 형식의 함수 정의를 찾을 수 없습니다.

이 코드에서 유용한 점은 일반 =가 자체 유형을 자체 참조로 변환한다는 것입니다. 그러나 이 =는 int를 매개변수로 사용하고 클래스 유형의 참조는 반환된 연산자입니다. 그러므로 문제를 볼 수 있으므로 단서를 나열합니다(단서는 링크된 기사의 원문에서 옮겨왔습니다).

1. 각 클래스 객체 인스턴스가 생성될 때 사용자가 "할당 연산자 오버로드 함수"를 정의하지 않으면 컴파일러는 자동으로 암시적 및 기본 "할당 연산자 오버로드 함수"를 생성합니다. 따라서 B1의 실제 선언은 다음 상황과 유사해야 합니다:
class A1
{ public:         int 연산자=(int a)         {                 return 8;         }         int Operator+(int a)         {                 return 9;         } }; class B1 : public A1 { public:         B1& 연산자 =(const B1& robj); // 이 줄은 컴파일러에 의해 추가된다는 점에 유의하세요         int 연산자-(int a)         {                 return 7;         } };






















2. C++ 표준에서는 다음과 같이 규정합니다. 파생 클래스에 선언된 멤버가 기본 클래스의 멤버와 동일한 이름을 갖는 경우 멤버의 데이터 유형 및 매개변수 수가 있더라도 기본 클래스의 멤버를 덮어씁니다. 기본 클래스의 멤버와 파생 클래스의 멤버는 완전히 다릅니다. . B1의 할당 연산자 함수 이름인 =는 기본 클래스 A1의 = 연산자와 이름이 동일합니다. 따라서 A1의 할당 연산자 함수 int Operator=(int a);는 암시적 할당 연산자 함수로 대체됩니다. B1.B1& 연산자 =(const B1& robj);가 적용되었습니다. A1의 int 연산자=(int a); 함수는 B1 개체에서 액세스할 수 없습니다.

3. 프로그램의 v = 2 문은 실제로 v.operator =(2);와 동일하지만 A1의 int 연산자=(int a);가 적용되어 액세스할 수 없습니다. 그리고 B1의 기본 B1& 연산자 =(const B1& robj); 함수는 매개변수 2의 정수형과 일치하지 않으므로 호출할 수 없습니다.

4. B1에 기본 B1& 연산자 =(const B1& robj); 함수가 있는지 확인하려면 다음 코드를 사용하여 확인할 수 있습니다:
B1 b;
B1 v;
v = b; // OK, 호출과 동일 v.operator =( b);

5. 따라서 "대입 연산자 오버로드 함수"를 파생 클래스가 상속할 수 없는 것이 아니라 파생 클래스의 기본 "할당 연산자 오버로드 함수"로 재정의하는 것입니다.

이것이 C++ 할당 연산자 오버로드 함수가 파생 클래스에서 상속될 수 없는 실제 이유입니다!

여기서 제가 문제라고 생각하는 부분을 발견했는데, 바로 2조: " 파생 클래스에 선언된 멤버가 기본 클래스의 멤버와 이름이 같은 경우 기본 클래스의 멤버를 덮어쓰게 됩니다 ."라는 내용 입니다. 가상 함수는 이 재정의 기능을 사용하여 비가상 함수인 경우 객체 참조 또는 포인터의 유형에 따라 Operator=()가 기본 클래스를 사용할지 파생 클래스를 사용할지 여부를 결정합니다. 따라서 기사의 예에서 문제는 A1의 메서드를 덮어썼는지 여부가 아니라 "B1의 기본 B1& 연산자 =(const B1& robj); 함수가 매개변수 2의 정수형과 일치하지 않아 호출할 수 없기 때문입니다. . ". 이는 원제목의 "대입 연산자는 왜 상속받을 수 없는가?"라는 질문에 대한 답변입니다. 이 예의 계산 과정을 변경하면 타입 매칭 이후에도 상속이 가능함을 알 수 있습니다.

        그럼, "왜 대입 연산자인 Operator=()가 가상 함수를 사용할 수 없는가"라는 질문으로 돌아가보겠습니다.

기본 클래스의 연산자=()가 가상 함수라고 가정합니다. 다음은 또 다른 예입니다.

DerivedClass a; // 파생 클래스 객체 a

DerivedClass b; // 파생 클래스 객체 b

BaseClass &c = a;//기본 클래스에 대한 포인터 또는 참조는 괜찮습니다. c

BaseClass &d = b;//기본 클래스에 대한 포인터 또는 참조가 d를 수행합니다.

a = b;//A.operator=(const DerivedClass & B) 호출

B가 자신이 정의한 할당 연산자를 잊어버린 경우 컴파일러는 우리를 위해 기본 연산자를 생성합니다. a의 복사 프로세스 중에 멤버별 얕은 복사 할당 방법인 이 기본 연산자=()가 사용됩니다. 참고: 파생 클래스 멤버) 이는 동적으로 관리되지 않는 파생 클래스에는 문제가 되지 않지만 문자열이나 새 작업이 있는 파생 클래스에는 불가능합니다. 그러나 사용자가 가상 ​​할당 연산자를 다시 정의하면 올바른 다시 쓰기를 통해 할당을 올바르게 구현할 수 있습니다.

반면, 가상 함수를 사용하지 않는 경우 기본 클래스의 할당 연산자를 사용하여 멤버별 할당(참고: 기본 클래스 멤버는 변경되고 파생 클래스 멤버는 변경되지 않음)을 수행하는 경우에도 문제가 발생합니다. 그래서 결론은 이전과 같고, 불가능하지는 않으나, 구체적인 상황과 결합하여 올바르게 구현되어야 한다는 것이다.


Guess you like

Origin blog.csdn.net/m0_38084180/article/details/80553804