본문 바로가기
IT/IT 잡지식

invalid new-expression of abstract class type error 해결 하기

by 큰공 2021. 7. 27.
728x90
반응형

 

개요

 c++ 코딩 중 상속한 Listener 의 Call Back 함수를 override 하는 과정에서 나타나는 아래 에러가 왜 발생하는지, 어떻게 해결 할 수 있는지 살펴 보자.

 

abstract 에러

/include/c++/9.3.0/ext/new_allocator.h:145:20: error: invalid new-expression of abstract class type

 

 살짝 생소한 에러가 발생한다. 에러의 위치도 정확하게 찍어주지 않고, new_allocator.h 라는 C++ 에 있는 기본 헤더파일에서 빌드에러가 발생한다.

 

 뒤에서 자세하게 설명하겠지만, 이는 추상화 클래스를 상속 받았는데, 그것을 올바르게 구현하지 않았을 때 발생한다.

 

 

OVERRIDE

A.h:13:10: error: 'void A::onA(State)' marked 'override', but does not override

 

 상기 에러가 발생하기 전에 override 에러가 발생을 했고, 해당 override 된 함수임에도 불구하고, override 된 함수가 아니라는 에러메시지가 발생을 해서, 과감하게 override 구문을 삭제하였다.

 

 override 구문을 삭제 했음에도, 여전히 abstract 에러는 발생을 한다.

 

 

 

해결

 이런 글을 검색하다보면 해결책을 제일 마지막에 두는 법이긴 하지만, 살짝 두괄식으로 해결책을 먼저 작성해보도록 보도록 하겠습니다.

 

 아래를 보고 Before / After 의 차이가 무엇일까요?

 

 Before

/** A.h **/
class A : public IAListener {
public:
    A();
    ~A();
    void onA(State mState) override;
};

/** A.cpp **/
#include "A.h"

A::A() {
}

A::~A() {
}

void A::onA(State mState) {
}

/** IAListener.h **/
class IAListener {
public:
    IAListener() = default;
    virtual ~IAListener() = default;
    virtual void onA(State& mState) = 0;
};

 

 After

/** A.h **/
class A : public IAListener {
public:
    A();
    ~A();
    void onA(State& mState) override;  // 에러 발생 부분 수정
};

/** A.cpp **/
#include "A.h"

A::A() {
}

A::~A() {
}

void A::onA(State& mState) {  // 에러 발생 부분 수정
}

/** IAListener.h **/
class IAListener {
public:
    IAListener() = default;
    virtual ~IAListener() = default;
    virtual void onA(State& mState) = 0;
};

어디가 달라졌는지 보이시나요? 바로 Type State 의 "&" 때문이였습니다.

 

처음에 override 관련 에러가 발생하길래, IAListener 에서 분명 해당 함수가 있는데, 왜 override 가 안되지? 라고 고민하다가 그냥 지워서 빌드만 되게 하자.. 였는데, 그게 화근이였나 봅니다.

 

virtual class 의 추상화 클래스와, 구현 class 의 실제 상속 받는 class 의 함수 형태와 인자가 동일해야 함에도, 자세히 안보고 그냥 넘겨서 이런 실수가 발생하였네요.

 

왜지? 왜지? 하면서 디버깅 시간을 많이 소모 했네요.

 

추상 클래스 (abstract class)

 그럼 이와 같은 에러가 왜? 생기는지 자세하게 파악 해보도록 하겠습니다.

 먼저, C++ 에서의 추상 클래스 (abstract class) , 순수 가상 함수 ( pure virtual function ) 를 알아 볼 필요가 있습니다.

 

추상 클래스 (abstract class)

 C++에서는 하나 이상의 순수 가상 함수를 포함하는 클래스를 추상 클래스(abstract class)라고 합니다.

이러한 추상 클래스는 객체 지향 프로그래밍에서 중요한 특징인 다형성을 가진 함수의 집합을 정의할 수 있게 해줍니다.

즉, 반드시 사용되어야 하는 멤버 함수를 추상 클래스에 순수 가상 함수로 선언해 놓으면, 이 클래스로부터 파생된 모든 클래스에서는 이 가상 함수를 반드시 재정의해야 합니다.

 

추상 클래스는 동작이 정의되지 않은 순수 가상 함수를 포함하고 있으므로, 인스턴스를 생성할 수 없습니다.

따라서 추상 클래스는 먼저 상속을 통해 파생 클래스를 만들고, 만든 파생 클래스에서 순수 가상 함수를 모두 오버라이딩하고 나서야 비로소 파생 클래스의 인스턴스를 생성할 수 있게 됩니다.

하지만 추상 클래스 타입의 포인터와 참조는 바로 사용할 수 있습니다.

출처 : http://tcpschool.com/cpp/cpp_polymorphism_abstract

 

 

 무슨 말인지, 이해가 되시나요?

 제가 이해한대로 좀 더 보충 설명을 해보겠습니다. 추상 클래스 (작업 지시자) 는 실체 클래스 (작업자) 에게 일을 시킬려고 하는데, 일종의 메뉴얼을 주고 싶습니다. 실체 클래스 (작업자) 가 마음대로 공구 (함수) 를 사용하지 않게 하기 위해서, 작업 지시자가 원하는 공구 ( 가상 함수 ) 을 두고 싶을 때 사용한다고 보면 될거 같습니다.

 

 위 코드에서는 IAListener 가 추상 클래스 ( 작업 지시자 ) 역할 이며, Class A 는 실체클래스 (작업자) 가 되게 됩니다. Class A는 IAListener 을 상속 받게 되고, IAListener 는 onA 라는 가상 함수를 통해서, Class A가 이를 강제적으로 사용하도록 제한 (지시) 합니다.

 

순수 가상 함수 ( pure virtual function ) 

 C++에서 가상 함수(virtual function)는 파생 클래스에서 재정의할 것으로 기대하는 멤버 함수를 의미합니다.

따라서 가상 함수는 반드시 재정의해야만 하는 함수가 아닌, 재정의가 가능한 함수를 가리킵니다.

 

이와는 달리 순수 가상 함수(pure virtual function)란 파생 클래스에서 반드시 재정의해야 하는 멤버 함수를 의미합니다.

이러한 순수 가상 함수는 일반적으로 함수의 동작을 정의하는 본체를 가지고 있지 않습니다.

따라서 파생 클래스에서 재정의하지 않으면 사용할 수 없습니다.

 

C++에서 순수 가상 함수는 다음과 같은 문법으로 선언합니다.

문법

virtual 멤버함수의원형=0;

 

위와 같이 함수만 있고 본체가 없다는 의미로 함수 선언부 끝에 "=0"을 추가합니다.

출처 : http://tcpschool.com/cpp/cpp_polymorphism_abstract

 

 

 

 이 또한, 딱딱한 글씨로 보면 와 닿지 않아, 쉽게 한번 설명해 볼까 합니다.

 

 추상 클래스 (작업 지시자) 가 실체 클래스 ( 작업자 ) 에게 일을 시킬려고 하는데, 이 공구 (함수) 는 써라~ 라고 할 때 가상 함수를 사용한다고 말했는데요. 순수 가상 함수 ( pure virtual function) 은 추상 클래스가 실체 클래스에게 꼭!! 이 함수를 재정의해서 사용하라라고 제한을 둘 때 사용 합니다.

 

 사용 안해서도 안되고, 꼭 이러한 형태로 사용하라고 명시하는 역할이죠. 실체 클래스는 이 순수 가상 함수를 정확하게 사용하지 않으면 안됩니다.

 

 위의 에러는 이 순수 가상 함수를 정확하게 ( 함수 인자의 형식까지도 동일하게 ) 사용하지 않아서 발생하는 빌드 에러 였습니다.

 

 

맺으며

error: invalid new-expression of abstract class type 에러 발생 시, 추상 클래스의 순수 가상 함수가 override 가 함수명 함수 인자까지 정상적으로 사용되었는지 확인하라.

 

 

 

728x90
반응형

댓글