문제

우리는 클래스가 7 개 이상의 클래스의 기본 클래스 역할을 할 수 없다는 제한이 있습니다. 컴파일 타임에 위의 규칙을 시행 할 수있는 방법이 있습니까?

나는 수업이 상속되는 것을 막기 위해 Andrew Koenig의 usable_lock 기술을 알고 있지만 수업을 인스턴스화하려고 할 때만 실패 할 것입니다. 스스로를 도출 할 때는 할 수 없습니까?

기본 클래스는 자녀가 누구인지 알 수 있습니다. 그래서 우리는 친구 수업의 조합을 선언 하고이 규칙을 시행하기 위해 캡슐화 할 수 있다고 생각합니다. 우리가 이런 식으로 시도한다고 가정 해 봅시다

class AA {
   friend class BB;
   private:
      AA() {}
      ~AA() {}
};

class BB : public AA {

};

class CC : public AA 
{};

클래스 CC의 도출은 접근 할 수없는 DTOR를 경고하는 컴파일러 경고를 생성합니다. 그런 다음 컴파일러 조정을 사용하여 오류와 같은 경고를 표시 할 수 있지만 (모든 경고와 같은 오류로서) 그러한 기술에 의존하고 싶지는 않습니다.

또 다른 방법이지만 나에게는 다소 어색한 것 같습니다.

class B;

class InheritanceRule{
    class A {
    public:
        A() {}
        ~A() {}
    };
    friend class B;
};

class B {
public:
    class C : public InheritanceRule::A
    {};
};


class D : public InheritanceRule::A{};

클래스 D의 파생은 컴파일러 오류로 표시됩니다. 즉, 파생 될 모든 클래스는 클래스 B 내부에서 파생되어야 함을 의미합니다.이를 통해 클래스 A에서 파생 된 클래스 수를 검사 할 수는 있지만 더 많은 것을 추가하지 못하게합니다. .

여기에서 할 수있는 방법이있는 사람이 있습니까? 기본 등급이 자녀가 누구인지 알 필요가 없다면 여전히 더 좋습니다.

참고 : 기본 클래스 역할을하는 클래스는 그 자체로 인스턴스화 될 수 있습니다 (추상적이 아님).

미리 감사드립니다.

편집 -1 : Jon.h의 의견에 따라 약간 수정되었습니다.

// create a template class without a body, so all uses of it fail
template < typename D> 
class AllowedInheritance;

class Derived; // forward declaration
// but allow Derived by explicit specialization 
template<> 
class AllowedInheritance< Derived> {};

template<class T>
class Base : private AllowedInheritance<T> {};

// privately inherit Derived from that explicit specialization    
class Derived : public Base<Derived> {};

// Do the same with class Fail Error
// it has no explicit specialization, so it causes a compiler error
class Fail : public Base<Fail> {}; // this is error

int main()
{   
   Derived d;

   return 0;
}
도움이 되었습니까?

해결책

나는 쓰레기처럼 피곤하고, 눈을 뜨고 간신히 유지할 수 있으므로 아마도 더 우아한 방법이있을 것입니다. 그리고 기지가 최대 7 개의 서브 클래스를 가져야한다는 기괴한 아이디어를지지하지 않습니다.

// create a template class without a body, so all uses of it fail
template < typename D, typename B> class AllowedInheritance;


class Base {};
class Derived; // forward declaration

// but allow Derived, Base by explicit specialization 

template<> class AllowedInheritance< Derived, Base> {};

// privately inherit Derived from that explicit specialization    
class Derived : public Base, private AllowedInheritance<Derived, Base> {};


// Do the same with class Compiler Error
// it has no explicit specialization, so it causes a compiler error
class CompileError: public Base, 
     private AllowedInheritance<CompileError, Base> { };

//error: invalid use of incomplete type 
//‘struct AllowedInheritance<CompileError, Base>’


int main() {

   Base b;
   Derived d;
   return 0;
}

Jon.h의 의견 :

예를 들어이 중지 방법 : 클래스 실패 : 공공 기지 {}; ?

그렇지 않습니다. 그러나 OP의 원래 예제도 마찬가지였습니다.

OP에 : 내 대답에 대한 귀하의 개정은 Coplien의 "호기심이 많은 반복 템플릿 패턴"을 직접적으로 적용하는 것입니다.]

나는 그것을 고려했지만, 문제는 derived1 : pubic base<derived1> 그리고 a derived2 : pubic base<derived2>, 왜냐하면 base<derived1> 그리고 base<derived2> 완전히 관련이없는 두 개의 클래스입니다.

유일한 우려가 구현 상속 인 경우 문제가되지 않지만 인터페이스 상속을 원한다면 솔루션이 중단됩니다.

상속 재산과 깨끗한 구문을 모두 얻는 방법이 있다고 생각합니다. 내가 언급했듯이 솔루션을 썼을 때 나는 꽤 피곤했다. 다른 것이 없다면, RealBase를 예제에서 기본베이스 클래스로 만들면 빠른 수정입니다.

이것을 청소하는 방법에는 여러 가지가있을 것입니다. 그러나 나는 Markh44에 동의한다는 것을 강조하고 싶습니다. 솔루션이 더 깨끗하지만, 우리는 여전히 의미가없는 규칙을 지원하는 코드를 혼란스럽게하고 있습니다. 이 작업이 수행 될 수 있다고해서 그렇게해야한다는 의미는 아닙니다.

문제의 기본 클래스가 열 살이고 너무 깨지기가 너무 깨지기 쉬운 경우, 실제 대답은이를 고치는 것입니다.

다른 팁

죄송합니다. 컴파일러를 사용하여 그러한 제한을 시행하는 방법을 모르겠습니다.

개인적으로 나는 규칙을 코드 자체로 강제하려고 노력하지 않을 것입니다. 코드가 수행하는 작업과 관련이없는 것들로 코드를 어지럽히고 있습니다. 클린 코드가 아닙니다.

후프를 뛰어 넘기보다는 그 규칙을 편안하게하려고 노력했습니다. 대신 필요한 경우 파손될 수 있고 팀의 다른 사람들과 일치 할 수있는 지침이어야합니다.

물론, 나는 당신이하고있는 일에 대한 지식이 부족합니다. ~할 수 있었다 적절하지만 일반적으로 그렇지 않을 것입니다.

X를하지 말아야한다고 말하는 모든 프로그래밍 "규칙"은 항상 y를해야합니다. 거기에 "거의"라는 단어를 주목하십시오.

때때로 당신은 할 수 있습니다 필요 7 개 이상의 파생 수업 - 그때 무엇을합니까? 더 많은 후프를 뛰어 넘으십시오. 또한 왜 7인가? 왜 6 또는 8이 아닌가? 그것은 단지 너무 임의적입니다 - 가난한 규칙의 또 다른 징후.

JP가 말한 것처럼 정적 분석이 더 나은 방법 일 것입니다.

다양한 정적 코드 분석 도구 중 다수는 상속 계층에 대한 정보를 제공합니다. 코드에서 처리하려고 시도하는 대신 상속 계층에 대한 규칙을 설정하고 해당 규칙을 따르지 않으면 빌드에 실패 할 수있는 도구를 살펴 보겠습니다. 약간의 비용이들 수 있으며 사용자 정의 규칙을 작성해야 할 수도 있습니다 (상속 깊이를 보았지만 상속을 보았지만 원하는대로 "폭"이 아닙니다). 그러나 장기적으로는 그것이 당신의 최선의 방법이라고 생각합니다.

의견 당 : 나는 사용했습니다 은폐 약간의 성공으로. 비트가 촉진됩니다. 거기 있습니다 몇 가지 좋은 스레드 더 나은 옵션이있을 수 있습니다.

주장으로 코드를 어지럽히는 대신 GCC-XML, G ++ 컴파일러 프론트 엔드를 사용하여 C ++ 소스를 구문 분석하고 XML 출력을 생성합니다. 나는이 출력을 구문 분석하고 규칙 위반을 확인하는 도구를 개발하는 것이 합리적으로 간단 할 것으로 기대합니다. 그런 다음 소스 코드 체크인과 통합 될 수 있습니다.

BTW, 기본 계급이 자손에 대해 알고 있으면 개방형 원칙, 그것은 실제로 OO 프로그래밍의 유용성을 일반적으로 과소 평가한다는 것을 의미합니다. 그만큼 주된 이유 코드를 기본 클래스 및 서브 클래스로 분리하려면 기본 클래스가 알 필요가 없습니다 서브 클래스에 대해 - 설치 후 전달 된 플러그인 패키지와 같은 가능한 항목이 가능합니다.

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