매개 변수가없는 비 푸시 가상 함수는 실습이 좋지 않습니까?

StackOverflow https://stackoverflow.com/questions/260380

  •  06-07-2019
  •  | 
  •  

문제

선택적인 가상 기능이있는 기본 클래스가 있습니다.

class Base {
    virtual void OnlyImplementThisSometimes(int x) {}
};

이것을 컴파일하면 사용하지 않은 Param X에 대한 경고를받습니다. 가상 기능을 구현해야 할 다른 방법이 있습니까? 나는 이것처럼 그것을 다시 작성했다.

class Base {
    virtual void OnlyImplementThisSometimes(int x) 
    {
        x = 0;
    }
};

또한 조심하지 않으면 서브 클래스가 잘못된 기능을 구현할 수 있고 과부하로 인해 눈치 채지 않는 문제가 있습니다.

class Derived : public Base {
    void OnlyImplementThisSometimes(int x, int y) { // some code }
};

Derived d;
Base *b = dynamic_cast<Base *>(&d);
b->OnlyImplementThisSometimes(x); // calls the method in the base class

"int y"매개 변수로 파생 된 함수를 구현했지만 기본 클래스 방법이 호출되었지만 이에 대한 경고는 없습니다. C ++에서 일반적인 함정입니까 아니면 가상 기능을 오해 했습니까?

도움이 되었습니까?

해결책

디자인 문제를 무시하면 변수 이름을 생략하여 사용하지 않는 변수에 대한 컴파일러 경고를 둘러 볼 수 있습니다.

virtual void OnlyImplementThisSometimes(int ) { }

가상 함수를 무시하려고 할 때 잘못된 메소드 서명을 실수로 구현하는 것은 C ++에서주의해야 할 것입니다. C#과 같은 언어는 '재정의'키워드를 사용하여이를 해결합니다.

다른 팁

우리는 매크로를 정의합니다 _unused 처럼:

#define _unused(x) ((void)x)

그런 다음 함수를 다음과 같이 정의합니다.

virtual void OnlyImplementThisSometimes(int x) { _unused( x );}

이것은 컴파일러가 불만을 제기하는 것을 막을뿐만 아니라 X에 대해 잊지 않은 코드를 유지 관리하는 사람에게는 분명합니다. 의도적으로 그것을 무시합니다.

기본 클래스에서 왜 정의합니까? 기본 클래스가 메소드를 사용하지 않으면 파생 클래스에서이를 가상 메소드로 정의하십시오.

또는 기본 구현은 예외를 던질 수 있습니다

가상 기능의 기본 구현을 제공하는 경우 해당 기능을 무시하지 않는 모든 파생 클래스에 대한 올바른 구현 여야합니다. 당신이 제공 할 수 없다면 옳은 구현은 순수한 가상 기능을 만들고 구현을 제공하기 위해 파생 클래스에 맡기는 것입니다. 메소드를 호출 할 수없는 파생 클래스는 실수로 사용되지 않도록 예외를 던질 수 있습니다.

변수 이름을 생략하는 것 외에도 많은 컴파일러에서 컴파일러를 알릴 수 있습니다.

int func(int x)
{
   (void) x;
}

이것은 내 코드에서 다소 일반적입니다. 예를 들어, 단일 스레드 작업 및 멀티 스레드 용으로 설계된 클래스가 있습니다. 일반적인 루틴과 데이터가 많이 있습니다. 나는 그 모든 것을 기본 클래스에 넣었습니다 (몇 가지 순수한 가상도 있습니다).

기본 클래스에서 init () 및 cleanup ()에서 두 가지 빈 가상 함수를 구현합니다. 단일 스레드 파생형 클래스는 그들을 묵상하지 않지만 뮬리트 스레드 클래스는 그렇습니다.

공장 기능이있어 적절한 파생 클래스를 작성한 다음 포인터를 반환합니다. 클라이언트 코드는 기본 클래스 유형에 대해서만 알고 있으며 init () 및 cleanup () 호출됩니다. 두 시나리오 모두 옳은 일을합니다.

물론,이 작업을 수행하는 방법에 대한 다른 좋은 제안이있을 수 있지만,이 관용구는 내 코드의 많은 부분에 적합합니다.

그것은 나쁜 연습이 아니며 구현할 수있는 클래스의 일부를 지정하는 일반적인 관용구입니다.

현재 사용자 입력 시스템에 사용하고 있습니다. 해당 클래스의 사용자가 모든 단일 방법을 구현하는 것이 지루하기 때문입니다.

class mouse_listener{
public:
    virtual ~mouse_listener() {}

    virtual void button_down(mouse_button a_Button) {}
    virtual void button_up(mouse_button a_Button) {}
    virtual void scroll_wheel(mouse_scroll a_Scroll) {}
    virtual void mouse_move_abs(math::point a_Position) {}
    virtual void mouse_move_rel(math::point a_Position) {}
};

BTW, 기본 클래스를 알고 있다면 역학을 수행 할 필요가 없습니다. 위로-캐스트, 즉 파생에서 기본으로.

Base *b = &d;

마찬가지로 할 것입니다. dynamic_cast<> 대신 아래로 캐스트 할 때 사용해야합니다. 즉, 기본에서 파생까지 :

if((Derived *d = dynamic_cast<Derived *>(b)) != 0)
{
  // use d
}

(물론 다운 캐스트의 경우 static_cast<> 일반적으로도 작동합니다.)

이 시도:

class Base {
    virtual void OnlyImplementThisSometimes(int x) = 0;
};

내가 그런 일을 한 이후로 오랜 시간이 지났지 만 그것이 당신이 가상 기능을 선언하는 방법이라고 생각합니다.

또한 다른 사람들이 말했듯이 변수 이름은 이와 같은 기능 선언에서 선택 사항입니다.

이것에 대한 가장 간단한 대답은 다음과 같습니다.

class Base {
    virtual void OnlyImplementThisSometimes(int x) { x;}
};

전혀 아무것도하지 않는 변수에 대한 간단한 참조는 모든 경고를 제거합니다 (VC ++에서 가장 높은 수준에서).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top