C ++에서 다른 (관련되지 않은!) 클래스의 기본 클래스에서 파생 클래스의 개체 참조

Cantordust

처음부터 질문 제목을 이해하지 못한다면 그것은 당신의 잘못이 아닙니다. 더 나은 설명을 생각할 수 없었습니다. 다음은 문제에 대한 설명입니다. 다소 시간이 걸릴 수 있으므로 미리 사과드립니다.

내 프로그램의 초기 버전에는 Ecosystem 클래스와 Individual 클래스가있었습니다.

// Very simplified, for illustration purposes

class Ecosystem
{
    protected:
        // The int is just the ID of the individual.
        std::map<int, std::shared_ptr<Individual> > individuals;

    public:
        Ecosystem();
        void func(int _individual_id)
        {
            std::cout << "Individual's age: " 
                      << individuals[_individual_id]->get_age() 
                      << std::endl;
        }

        void routine(int _individual_id)
        {
            // Another function working via
            // the pointers in individuals.
        }        

        // More such functions...
};

class Individual
{
    protected:
        int age;

    public:
        Individual();
        inline int get_age() const
        {
            return age;
        }
};

Ecosystem 클래스에는 수십 개의 기능이 포함되어 있으며 앞으로 더 많은 기능을 추가 할 것입니다.

이제 Individual 클래스를 기본 클래스와 TypeAIndividual 및 TypeBIndividual과 같은 두 개의 파생 클래스로 분할하기로 결정했습니다. 각각 다른 클래스에 필요하지 않은 멤버와 특성이 있기 때문입니다 (기본 클래스를 통해 몇 개의 멤버와 특성도 공유하기 때문입니다). ). 따라서 기본 Individual 클래스와 두 개의 파생 클래스가 있습니다.

class TypeAIndividual : public Individual
{
    protected:
        // Data structures specific to individuals of type A

    public:
        TypeAIndividual();
};

class TypeBIndividual : public Individual
{
    protected:
        // Data structures specific to individuals of type B

    public:
        TypeBIndividual();
};

문제는 생태계가 이제 TypeAEcosystem과 TypeBEcosystem으로 분리되어야한다는 것입니다.

class Ecosystem
{
    protected:
        // Holding pointers to the base Individual class is pointless (pun not intended)
        // std::map<int, std::shared_ptr<Individual> > individuals;

    public:
        Ecosystem();
        // I want to keep func() in the base class
        // because it only accesses attributes and
        // members common to both classes derived
        // from Individual. 
        void func(int _individual_id)
        {
            // Hmmmm...
            // The pointers don't live in the Ecosystem class any more!
            std::cout << "Individual's age: " 
                      << individuals[_individual_id]->get_age() 
                      << std::endl; 
        }
        // OK to implement in each class
        // derived from Ecosystem.
        virtual void routine(int _individual_id) = 0;
};

class TypeAEcosystem : public Ecosystem
{    
    protected:
        // Pointers to individuals
        // of the corresponding type.
        std::map<int, std::shared_ptr<TypeAIndividual> > individuals;

    public:
        TypeAEcosystem();
        // Reimplementing routine() is OK
        // because it does things specific to
        // this individual type.
        virtual void routine (int _individual_id)
        {
            // Operate on data structures particular
            // to this type of individual.
        }

};

class TypeBEcosystem : public Ecosystem
{
    protected:
        // Pointers to individuals
        // of the corresponding type.
        std::map<int, std::shared_ptr<TypeBIndividual> > individuals;

    public:
        TypeBEcosystem();
        // Reimplementing routine() is OK
        // because it does things specific to
        // this individual type.
        virtual void routine (int _individual_id)
        {
            // Operate on data structures particular
            // to this type of individual.
        }
};

TypeAEcosystem과 TypeBEcosystem은 모두 void func(int _individual_id)해당 유형의 개인에 액세스 해야하는를 사용 합니다. 그러나 기본 클래스 Ecosystem은 더 이상 개인에 대한 포인터를 포함하지 않습니다. std::maps는 기본 클래스가 아닌 각 파생 클래스에 있기 때문 입니다.

내 질문은 : 생태계에서 파생 된 각 클래스에서 별도의 구현을 피하면서 적절한 유형의 개인 ( TypeAIndividual또는 TypeBIndividual)에 액세스하려면 어떻게 void func(int _individual_id)해야합니까? 즉, func()변경시 파생 클래스를 변경할 필요가 없도록 기본 클래스 를 유지하는 방법이 있습니까? 실제 프로그램에는 하나만 매개 변수로 사용하는 수십 개의 함수 func()가 있습니다 int. 또한 이러한 함수 중 일부는 Ecosystem클래스의 다른 구조에서 개별 ID를 가져 오므로 단순히 TypeAIndividual또는에 대한 포인터를 전달할 수 없습니다 TypeBIndividual.

내가 고려한 것들

  • 두 파생 클래스에 필요한 모든 데이터 구조 를 사용하여 공통 클래스 병합 TypeAIndividual하고 TypeBIndividual다시 되돌립니다 Individual. 이것은 특히 서투른 일을하는 방법으로 생각되지만 적어도 작동합니다.

  • 제작 func()및 (주) 가상과에서 구현 TypeAEcosystem하고 TypeBEcosystem. 즉, 기능 중 하나를 변경하려면 두 구현을 모두 변경해야합니다 (= 유지 관리의 악몽).

  • 다음 과 같이 두 가지 유형의 개인 Ecosystem을 보유하는 클래스가 하나뿐입니다 std::map.

    // Seems clunky...
    class Ecosystem
    {
        protected:
            // Note: The Ecosystem can contain 
            // one OR the other, but not both!
            // One map will always be empty.
        std::map<int, std::shared_ptr<TypeAIndividual> > type_a_individuals;
    
        std::map<int, std::shared_ptr<TypeBIndividual> > type_b_individuals;
    
        public:
            Ecosystem();
            void func(int _individual_id)
            {
                // Check what type of individuals we 
                // are working with and operate on the
                // appropriate container.
                if (type_a_individuals.size() > 0)
                {
                    std::cout << "Individual's age: " 
                              << type_a_individuals[_individual_id]->get_age() 
                              << std::endl; 
                }
                else
                {
                    std::cout << "Individual's age: " 
                              << type_b_individuals[_individual_id]->get_age() 
                              << std::endl; 
                }
            }
    };
    

이를 위해서는 모든 함수에 검사를 삽입해야하는데, 이는 별도의 클래스에 함수를 갖는 것만큼이나 유지 관리 측면에서 나쁘다.

참고 : 포인터 전달을 피하고 싶지만 문제가 해결되면 업 캐스팅 및 / 또는 다운 캐스팅을 적절하게 고려할 것입니다 (최후의 수단으로 ...).

어떤 제안이라도 환영합니다!


편집 1

환상적인 답변에 감사드립니다! amit과 Chris가 제안한 것처럼 내 Ecosystem수업을 보았고 충분히 확실하게 너무 부피가 커졌습니다. 멤버 함수를 다른 클래스로 옮겼고 이제 클래스에서 4 ~ 5 개의 필수 함수로 축소되었습니다 Ecosystem. Ecosystem클래스는 라이브러리에 상주하고 개인과 함께 실험을 수행 할 수있는 인터페이스를 제공하지만 사용자가 Individuals 및 기타 클래스를 직접 조작 할 수있는 것을 원하지 않으므로 완전히 제거 할 수는 없습니다.

나는 모든 제안을 좋아했고 몇 가지 독창적 인 해결책이 있습니다. 즉, Chris가 제안한 것은 매우 깔끔하고 세 개의 개별 클래스 (기본 및 두 개의 파생 클래스)가 아닌 단일 생태계 클래스를 가질 수 있다는 점에서 즉시 저의 관심을 끌었습니다. 개인의 유형은 구성 파일에 지정할 수 있으며 동일한 실험 내에서 서로 다른 구성 파일에서 여러 생태계를 생성 할 수 있습니다. 이것은 받아 들여지는 대답입니다.

건설적인 의견을 보내 주신 모든 분들께 다시 한 번 감사드립니다!

크리스

내 의견에서 이미 말했듯이 생태계를 템플릿 클래스로 만들고 각 IndivualType에 대해 하나의 생태계 인스턴스를 가질 수 있습니다.

template <class IndivualType>
class Ecosystem {
  protected:
    // The int is just the ID of the individual.
    std::map<int, std::shared_ptr<IndivualType> > individuals;
  public:
    // ...
};

주어진 IndividualType에 대해 생태계가 다르게 작동해야하는 경우 다음과 같이 명시 적으로 생태계를 전문화 할 수 있습니다.

template <>
class Ecosystem<SpecialIndividualType> {
protected:
        // The int is just the ID of the individual.
        std::map<int, std::shared_ptr<SpecialIndividualType> > individuals;
      public:
        // special implementation for EcoSystem for SpecialIndividualType 
};

이것은 아마도 필요하지 않을 수도 있지만 알아두면 좋을 것입니다.

마지막으로 말했듯이

Ecosystem 클래스에는 수십 개의 기능이 포함되어 있으며 앞으로 더 많은 기능을 추가 할 것입니다.

생태계의 기능을 정책으로 분할하는 것을 고려할 수 있습니다. 나는 당신의 필요를 모르지만 예를 들어 :

template <class IndivualType, class SomePolicy1, class SomePolicy2>
class Ecosystem {
  private:
    const SomePolicy1 mSp1;
    const SomePolicy2 mSp2;
  protected:
    // The int is just the ID of the individual.
    std::map<int, std::shared_ptr<IndivualType> > individuals;
  public:
    Ecosystem (const SomePolicy1& sp1= SomePolicy1(), const SomePolicy2& sp2= SomePolicy2())) : mSp1(sp1), mSp2(sp2) {}
    // ...
    void func(int _individual_id) 
        mSp1.doSmth(_individual_id);
    }

    void func2(int _individual_id) {
        mSp2.doSmth(_individual_id);
    }
};

이를 "정책 기반 설계"라고하며 웹에서 이에 대한 많은 정보를 찾을 수 있습니다.

물론 이미 언급 한 방법을 가상으로 만드는 것과 같은 다른 솔루션도 있습니다. 나는 아마도 (당신이 가진 시간에 따라) 둘 다 시도하고 당신이 가장 편안하다고 느끼는 것을 볼 것입니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

C ++에서 기본 및 파생 클래스 개체의 트리 구조

분류에서Dev

기본 참조 개체에서 파생 클래스의 멤버 호출

분류에서Dev

C ++ 클래스 및 상속 오류 : 파생 클래스에 대한 정의되지 않은 참조

분류에서Dev

C #의 파생 클래스 개체에서 새 기본 클래스 개체 만들기

분류에서Dev

한 개체의 클래스가 C ++에서 다른 개체의 클래스에서 파생되었는지 확인

분류에서Dev

XElement 기본 클래스의 메서드가 파생 클래스에 나타나지 않습니다.

분류에서Dev

정의되지 않은 참조 : 다른 클래스에서 개체의 포인터 배열을 초기화하려고합니다.

분류에서Dev

GCC 4.4.7에 의한 C ++ 개체 모델 : 파생 클래스 개체에서 차지하는 기본 클래스 하위 개체 패딩

분류에서Dev

파생 클래스에 대한 참조 함수에 기본 클래스의 개체 전달

분류에서Dev

파생 클래스에 대한 참조 함수에 기본 클래스의 개체 전달

분류에서Dev

기본 클래스에 대한 참조에 파생 클래스의 개체 저장

분류에서Dev

C ++의 기본 클래스에서 파생 클래스의 개체를 만드는 방법

분류에서Dev

파생 클래스 개체에 대한 기본 클래스 참조

분류에서Dev

C #의 다른 클래스에서 개체 ID 가져 오기

분류에서Dev

다른 클래스의 기본 클래스에서 개체 사용

분류에서Dev

기본 클래스에서 파생 클래스 개체 사용

분류에서Dev

다른 클래스의 개체에서 참조 변수

분류에서Dev

C ++ : 새 기본 클래스이지만 파생 클래스의 속성에 액세스 할 수 있습니다.

분류에서Dev

파생 클래스 C ++에서 기본 클래스 전용 멤버의 동작을 재정의합니다.

분류에서Dev

C ++의 파생 클래스에서 기본 클래스 메서드를 오버로드 할 수 없습니다.

분류에서Dev

다른 클래스에서 개조 클래스 초기화

분류에서Dev

생성자에서 클래스 멤버를 사용할 때 C ++ 정의되지 않은 참조

분류에서Dev

기본 클래스에서 파생 클래스의 다형성 확장

분류에서Dev

Python의 클래스 메서드에서 동일한 클래스의 다른 개체 참조

분류에서Dev

C ++ | 파생 클래스는 자체 개인 멤버가 아닌 기본 클래스의 개인 멤버에 액세스합니다.

분류에서Dev

오류 : BaseClass Father에서 Son 클래스를 파생 할 때 기본 클래스가 정의되지 않았습니다.

분류에서Dev

Eclipse에서 참조되지 않은 클래스 속성 찾기

분류에서Dev

다른 클래스 모듈에서 main에서 생성 된 클래스의 인스턴스 참조

분류에서Dev

Java의 다른 클래스에서 보이지 않는 초기화 된 객체

Related 관련 기사

  1. 1

    C ++에서 기본 및 파생 클래스 개체의 트리 구조

  2. 2

    기본 참조 개체에서 파생 클래스의 멤버 호출

  3. 3

    C ++ 클래스 및 상속 오류 : 파생 클래스에 대한 정의되지 않은 참조

  4. 4

    C #의 파생 클래스 개체에서 새 기본 클래스 개체 만들기

  5. 5

    한 개체의 클래스가 C ++에서 다른 개체의 클래스에서 파생되었는지 확인

  6. 6

    XElement 기본 클래스의 메서드가 파생 클래스에 나타나지 않습니다.

  7. 7

    정의되지 않은 참조 : 다른 클래스에서 개체의 포인터 배열을 초기화하려고합니다.

  8. 8

    GCC 4.4.7에 의한 C ++ 개체 모델 : 파생 클래스 개체에서 차지하는 기본 클래스 하위 개체 패딩

  9. 9

    파생 클래스에 대한 참조 함수에 기본 클래스의 개체 전달

  10. 10

    파생 클래스에 대한 참조 함수에 기본 클래스의 개체 전달

  11. 11

    기본 클래스에 대한 참조에 파생 클래스의 개체 저장

  12. 12

    C ++의 기본 클래스에서 파생 클래스의 개체를 만드는 방법

  13. 13

    파생 클래스 개체에 대한 기본 클래스 참조

  14. 14

    C #의 다른 클래스에서 개체 ID 가져 오기

  15. 15

    다른 클래스의 기본 클래스에서 개체 사용

  16. 16

    기본 클래스에서 파생 클래스 개체 사용

  17. 17

    다른 클래스의 개체에서 참조 변수

  18. 18

    C ++ : 새 기본 클래스이지만 파생 클래스의 속성에 액세스 할 수 있습니다.

  19. 19

    파생 클래스 C ++에서 기본 클래스 전용 멤버의 동작을 재정의합니다.

  20. 20

    C ++의 파생 클래스에서 기본 클래스 메서드를 오버로드 할 수 없습니다.

  21. 21

    다른 클래스에서 개조 클래스 초기화

  22. 22

    생성자에서 클래스 멤버를 사용할 때 C ++ 정의되지 않은 참조

  23. 23

    기본 클래스에서 파생 클래스의 다형성 확장

  24. 24

    Python의 클래스 메서드에서 동일한 클래스의 다른 개체 참조

  25. 25

    C ++ | 파생 클래스는 자체 개인 멤버가 아닌 기본 클래스의 개인 멤버에 액세스합니다.

  26. 26

    오류 : BaseClass Father에서 Son 클래스를 파생 할 때 기본 클래스가 정의되지 않았습니다.

  27. 27

    Eclipse에서 참조되지 않은 클래스 속성 찾기

  28. 28

    다른 클래스 모듈에서 main에서 생성 된 클래스의 인스턴스 참조

  29. 29

    Java의 다른 클래스에서 보이지 않는 초기화 된 객체

뜨겁다태그

보관