2016-11-05 14 views
0

나는 고급 프로그래머가 아닙니다.다이아몬드의 std :: unique_ptr을 통해 가장 기본 클래스의 보호 된 멤버 변수에 액세스 할 수 없습니다.

class Base 
class A: virtual public Base 
class B: virtual public Base 
class Last: public A, public B 

한다고 가정 Base 변수, m_x있다, 즉, A, 또는 B의 한, 한 번에 호출 할 수있는, AB에 공통 같은되지 않습니다 : 고전적인 다이아몬드 상속이 가정 둘 다 필요합니다. 이 문제를 얻으려면이 사용된다

class Last: public A, public B 
{ 
private: 
    std::unique_ptr<Base> m_p; 
public: 
    Last(int i) 
    { 
     if (i) 
      m_p = std::unique_ptr<Base>(new A()); 
     else 
      m_p = std::unique_ptr<Base>(new B()); 
    } 
}; 

이 괜찮지 만, 그것이 보호 말한다 때문에 지금 m_p->m_x 더 이상 액세스 할 수 없습니다,하지만 문제 직접 생성자 모두 AB 전화 m_x.

알려진 제한 사항입니까 아니면 잘못된 방법입니까? 그것이 틀린 경우, 거기에 어떤 해결책이 있습니까? 여기


는 도면에 기초하여 몇 가지 코드 (페이지에서 약간 아래) here 발견 : 때문에 컴파일 (답변이 코멘트에 따른) 모두 this->m_pthis->Power::m_x 사용

#include <iostream> 
#include <memory> 

class Power 
{ 
protected: 
    double m_x; 
public: 
    Power() {} 
    Power(double x): m_x {x} {} 
    virtual ~Power() = default; 
}; 

class Scanner: virtual public Power 
{ 
public: 
    Scanner() {} 
    Scanner(double x): Power(x) {} // scan document 
}; 

class Printer: virtual public Power 
{ 
public: 
    Printer() {} 
    Printer(double x): Power(x) {} // print document 
}; 

class Copier: public Scanner, public Printer 
{ 
private: 
    std::unique_ptr<Power> m_p; 
public: 
    Copier() {} 
    Copier(double x, int i) 
    { 
     if (i) 
      m_p = std::unique_ptr<Power>(new Scanner(x)); 
     else 
      m_p = std::unique_ptr<Power>(new Printer(x)); 
    } 
    void print() { std::cout << this->Power::m_x << '\n'; } 
}; 

int main(int argc, char *argv[]) 
{ 
    Copier *copier {new Copier(1.618, 0)}; 
    copier->print(); 
    copier = new Copier(3.14, 1); 
    copier->print(); 

    return 0; 
} 

되지만 출력 0입니다.


나는 모든 그것을 밖으로 철자 확인하려면 다음뿐만 아니라 꽤 초보자,하지만, 위의 예를 주어, 정말 Scanner 또는를 호출하는 또 다른 대안이있는 경우 그 상태를 유지해야 oesn't Printer 내부에서 한 번에 하나씩 Copier. 나는 의견을 묻는 것이 아니며, 금지되어 있다는 것을 이해하지만, 경험 많은 사용자로부터 오는 의견은 거부하지 않을 것입니다. 결국, 나는 배우 고있다.

+3

나는 'Last' * is-a * A와 * is-a * B가 어떻게되는지 이해하지 못한다. 그런데 A 나 B 중 하나가 나에게 의미가 없다. – nvoigt

+2

'm_p'는 기본 객체가 아닙니다. '이'입니다. –

+0

@CaptainGiraffe'm_p-> m_x'를 사용하는 대신'this-> m_x'를 사용해야합니까? 나는 단지'm_p'를'this'로 대체하고 컴파일하지만 작동하지 않는 것 같습니다. 변수는 모두 0입니다. 정교하게 제발 주시겠습니까? –

답변

2

protected 당신이 생각하는 바를 의미하지 않습니다. 일부 Last 개체의 하위 개체 단지 그 Base 객체 - Last 비록

Base에서 파생, Last의 멤버 함수는 의 보호 된 멤버 어떤Base 개체에 액세스 할 수 없습니다. *m_p은 정적 유형 Base의 때문에,하지 m_p->x*thisLast 개체입니다 this->Base::x 때문에,하지만 :

그래서 당신은 쓸 수 있습니다.

다른 사람들이 언급했듯이, 이것은 실제로는 XY problem이라고 생각합니다. 두 클래스에서 파생 된 객체를 갖는 다음 은 이러한 클래스 중 하나의 다른 객체에 대한 포인터를 가지고 있습니다. 실제로 매우 이상합니다. 나는 당신이 무엇을하려고하는지 명확히해야한다고 생각합니다.

+0

코드를 게시 할 수는 없지만 새로 편집 한 질문의 예가 ​​더 적합하기를 바랍니다. –

+0

아니, 두렵다. 방금 이름을 바꿨지만, 여전히 당신이하려는 것을 보지 못했습니다. 기본 클래스 "힘"은 무엇을 나타 냅니까? –

+0

나는 내 질문에 링크 후 예제를 줬다. 나는 파워 서플라이와 컨트롤 유닛이라고 생각할 수 있다고 생각한다. 그래서 당신은'm_x'가 스캐닝 후에 문서가 저장되는 저장 장치 (RAM, USB, 하드 디스크 등)이며 편집/인쇄/등을 위해 사용된다고 말할 수 있습니다. 그것은 추상적 인 예입니다. 또는 산업 기계 공장, 트랙터, 불도저 등을 작업 현장에서 한 번에 하나씩 작업하기 시작하는 것으로 생각할 수 있습니다. 이 줄에는 뭐든지있어. –

3

가상 상속과 std::unique_ptr은 모두 붉은 청어입니다. 문제는이 내려 온다 :

class Base 
{ 
protected: 
    int m_x; 
}; 

class Last : public Base 
{ 
public: 
    Last() 
    { 
     Base base; 
     base.m_x = 0; // error 
     m_x = 1; // no error 
    } 
}; 

오류가 error C2248: 'Base::m_x': cannot access protected member declared in class 'Base' 또는 error: 'int Base::m_x' is protected within this context 같은 것입니다.

설명은 protected은 다소 특별한 경우입니다. 이 아니라 클래스 수준에서만 작동하지만도 입니다. 하나는 this가 가리키는 즉, 생성자에 의해 생성되는

  1. Last 객체 : 그리고 당신은 여기에 두 개의 관련 개체가. 은 - 상속 관계이므로 Base 개체이기도합니다.
  2. 생성자 내에 base이라는 로컬 객체가 있습니다.

이제는 base.m_x = 0; 줄에 두 번째 것이 아니라 첫 번째 객체의 컨텍스트에있는 것이 문제입니다. 즉, base 외부에서 의 base에 액세스하려고합니다. C++은 이것을 허용하지 않습니다.

매우 기술적 인 설명은 §11.4 [class.protected]의 C++ 표준에서 찾을 수 있습니다. 여기에서는 스택 오버플로 excellent answer에서보다 쉽게 ​​이해할 수 있습니다.

+0

그런 다음 "붉은 청어"인 경우 피할 수 있습니까? 나는 대답을 편집했다, 나는 그것이 지금 더 분명해 졌기를 바란다. –

+1

@aconcernedcitizen : 질문에 [MCVE]를 표시하면 피할 수 있습니다. –

+0

@ LightnessRacesinOrbit 두 번째 예를 사용하여 답변을 수정했습니다. 크게는 기본적으로 내가하고 싶은 것입니다. 충분하지 않니? –