모든 가상 함수를 파생 클래스에서 구현해야합니까?


93

이것은 간단한 질문처럼 보일지 모르지만 다른 곳에서는 답을 찾을 수 없습니다.

다음이 있다고 가정합니다.

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Derived 클래스가 bar () 함수를 구현하지 않는 것이 괜찮습니까? 내 모든 파생 클래스에 bar () 함수가 필요한 것은 아니지만 일부는 필요합니다. 추상 기본 클래스의 모든 가상 함수를 파생 클래스에서 구현해야합니까, 아니면 순수 가상 인 것만 구현해야합니까? 감사

답변:


83

파생 클래스는 자체적으로 모든 가상 함수 를 구현할 필요가 없습니다 . 그들은 순수한 것을 구현하기 만하면 됩니다. 1 이것은 질문 의 클래스가 맞다는 것을 의미합니다 . 그것은 상속 조상 클래스의 구현을 . (이것은 어딘가에 구현되어 있다고 가정합니다 . 질문의 코드는 메서드를 선언하지만 정의하지는 않습니다. Trenki의 답변에 표시된 대로 인라인으로 정의하거나 별도로 정의 할 수 있습니다.)DerivedbarAbstractAbstract::bar


1 그리고 심지어 파생 클래스가 인스턴스화 되는 경우에만 . 파생 클래스가 직접 인스턴스화되지 않고 더 많은 파생 클래스의 기본 클래스로만 존재하는 경우 모든 순수 가상 메서드를 구현하는 것은 해당 클래스입니다. 계층 구조의 "중간"클래스는 기본 클래스와 마찬가지로 일부 순수 가상 메서드를 구현하지 않은 상태로 둘 수 있습니다. "중간"클래스 순수 가상 메서드를 구현하는 경우 그 후손은 해당 구현을 상속하므로 직접 다시 구현할 필요가 없습니다.


3
그리고 이것 (순수한 가상 함수의 구현)은 (추상 기본 클래스 자체와는 대조적으로) 인스턴스화되도록 의도 된 경우에만 가능합니다.
Christian Rau

1
그게 제가 생각한 것입니다. 하지만 내 프로젝트에서이 작업을 수행하고 있는데 Derived :: bar ();에 대해 "해결되지 않은 외부 기호"가 있다는 연결 오류가 발생합니다. 하지만 Derived 내에서 bar를 선언 한 적이 없는데 링커가 함수 본문을 찾는 이유는 무엇입니까?
mikestaub

1
@pixelpusher 물론 Derived::bar함수 본문이 Abstract::bar있습니다. 그래서 그것이 정의 된 번역 단위 (어디서나 정의되어 있습니까?)가 호출되는 번역 단위에 연결되지 않은 것 같습니다.
Christian Rau

2
@Rob : They only need to implement the pure ones.오해의 소지가 있습니다. 파생 클래스가 반드시 순수 가상 함수 를 구현할 필요 는 없습니다 .
Nawaz

나는 도움을 주셔서 감사하지만 @trenki는 머리에 못을 박았습니다. 정의되지 않았기 때문에 당신도 올바른 Christian Rau였습니다.
mikestaub

47

순수 가상 메서드 만 파생 클래스에서 구현되어야하지만 다른 가상 메서드에 대한 정의 (단순한 선언이 아닌)가 여전히 필요합니다. 하나를 제공하지 않으면 링커가 불평 할 수 있습니다.

따라서 {}선택적 가상 메서드 뒤에두면 빈 기본 구현이 제공됩니다.

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

더 복잡한 기본 구현은 별도의 소스 파일로 이동합니다.


7

ISO C ++ 표준은 순수 가상이 아닌 클래스의 모든 가상 메서드를 정의해야한다고 지정합니다.

간단히 말해서 규칙은 다음과 같습니다.
파생 클래스가 Base 클래스 가상 메서드를 재정의하면 정의도 제공해야합니다. 그렇지 않으면 Base 클래스가 해당 메서드의 정의를 제공해야합니다.

코드 예제의 위 규칙에 따라 virtual void bar();Base 클래스의 정의가 필요합니다.

참고:

C ++ 03 표준 : 10.3 가상 함수 [class.virtual]

클래스에서 선언 된 가상 함수는 정의되거나 해당 클래스에서 순수 (10.4)로 선언되거나 둘 다로 선언됩니다. 그러나 진단은 필요하지 않습니다 (3.2).

따라서 함수를 순수 가상으로 만들거나 정의를 제공해야합니다.

GCC의 자주 묻는 질문 doccuments뿐만 아니라 그것을 :

ISO C ++ 표준은 순수 가상이 아닌 클래스의 모든 가상 메서드를 정의해야하지만이 규칙 위반에 대한 진단은 필요하지 않음을 지정합니다 [class.virtual]/8. 이 가정을 기반으로 GCC는 암시 적으로 정의 된 생성자, 할당 연산자, 소멸자 및 첫 번째 비 인라인 메서드를 정의하는 번역 단위의 클래스 가상 테이블 만 내 보냅니다.

따라서이 특정 메서드를 정의하지 않으면 링커가 관련성이없는 기호에 대한 정의가 부족하다고 불평 할 수 있습니다. 안타깝게도이 오류 메시지를 개선하려면 링커를 변경해야 할 수 있으며 항상 그렇게 할 수있는 것은 아닙니다.

해결책은 순수하지 않은 모든 가상 메소드가 정의되도록하는 것입니다. 소멸자는 pure-virtual로 선언 된 경우에도 정의되어야합니다 [class.dtor]/7.


3

예, 괜찮습니다 ... 추상 기본 클래스에서 파생 된 클래스를 인스턴스화하려면 순수한 가상 함수 만 구현하면됩니다.


1

예, Derived 클래스가 부모 클래스에서 Pure Virtual 인 함수를 덮어 써야한다는 것이 맞습니다. 순수 가상 함수를 가진 부모 클래스는 자식 클래스가 순수 가상 함수의 자체 본문을 제공해야하기 때문에 추상 클래스 라고만합니다.

일반 가상 기능의 경우 :-일부 하위 클래스에 해당 기능이있을 수 있지만 일부는 없을 수 있으므로 추가로 재정의 할 필요가 없습니다.

가상 함수 메커니즘의 주된 목적은 순수 가상 함수 (Abstract Class)의 주 목적이 자신의 바디와 동일한 이름의 함수를 가져야하는 것이 든간에 런타임 다형성입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.