2010-06-21 2 views
11

질문 제목이 정확한지 확실하지 않습니다 ... 원래의 간단한 시나리오를 설명하고 시작하여 무엇을하고 싶은지 설명하고, 그러나 할 수 없다.값 별 전달 형 다형성

class Operand; 

Operand genOperandA() { ...; return Operand(); } 
Operand genOperandB() { ...; return Operand(); } 
... // more operand-generation functions 

typedef Operand (*OpGen)(); 

// Table of function pointers 
static const OpGen generators[] = 
{ 
    genOperandA, 
    genOperandB, 
    ... 
}; 

// Function to do some operation on the operand 
void operate(Operand& op); 

... 

// Example call 
operate(generators[1]()); 

지금까지 너무 좋아 (내 생각) :

원래 내가 좋아하는 뭔가를했다. 그러나, 몇몇 유도 된 피연산자 유형이 존재한다. class RegisterOperand : public Operand. 이상형으로 파생 된 유형의 인스턴스를 반환하는 새롭고 헌신적 인 genOperand 함수가 있습니다. 나는 참조 또는 포인터 형태를 돌려주는 것 인 경우에이 작동합니다 알고, 그래서 만, 그러나

RegisterOperand genOperandC() { ...; return RegisterOperand(); } 

static const OpGen generators[] = 
{ 
    ... 
    genOperandC, 
}; 

:

Operand genOperandC() { ...; return RegisterOperand(); } 

을 나는이 작업을 수행 할 수 없습니다 :하지만이 작업을 수행 할 수 없습니다 현재 가지고있는 옵션은 다음과 같습니다.

이제는 원래 필요하지 않은 명시 적 정리가 필요합니다.

내가 고려하지 않은 대안은 무엇입니까?

답변

4

포인터를 사용할 필요가없는 다른 디자인이있을 수도 있지만,이 방법이 필요하거나 원하는 경우 관심을 가질 수 있습니다. 포인터를 반환하는 것은 문제가 될 경우


(때문에 "청소"일을 할 필요성), 당신은 확실히 반환 형식으로 스마트 포인터를 사용하는 것이 좋습니다.

boost::shared_ptr<Operand> genOperandC() 
{ 
    return boost::shared_ptr<Operand>(new RegisterOperand()); 
} 

이 방법, 당신은 수동으로 delete를 호출 할 필요가 없습니다 : 여기

는 스마트 포인터와 팩토리 메소드의 예입니다 필요할 때 그것은 당신을 위해 boost::shared_ptr<Operand>의 소멸자에 의해 수행됩니다. 당신이 결과 포인터를 캐스팅 할 필요가 나중에 경우

, boost 제공뿐만 아니라 기능을 주조 :

boost::shared_ptr<Operand> op = genOperandC(); 

boost::shared_ptr<RegisterOperand> rop = 
    boost::dynamic_pointer_cast<RegisterOperand>(op); 
+1

공유 포인터를 직접 생성하는 대신에 boost :: make_shared를 사용하면 간단한 래퍼 메소드이지만 필요한 메모리 할당 횟수가 줄어 듭니다 (따라서 더 빠릅니다) –

7

당신은 포장 할 수 있습니다

class Operand 
{ 
public: 

private: 
    std::unique_ptr<OperandImpl> mImpl; 
}; 

이것은 전략 패턴과 유사하다 : 실제 피연산자 비헤이비어는 비공개 인터페이스를 통해 숨겨져 있으며 액세스 할 수 있습니다. 사용자는 Operand 사본을 얻습니다. 내부의 정보를 알 필요가 없으며이를 사용할 수 있으며 다양한 파생 된 동작을 자유롭게 구현할 수 있습니다.

+0

실제로 내 다른 하위 유형이 실제로 상속받을 생각입니까? 'OperandImpl', 그리고'Operand'에 대한 멤버 호출은 단순히 * mImpl'에 위임되어야합니까? –

+0

네, 이것은 전형적인 전략 패턴입니다. 실제 메모리 처리가 (OperandImpl로 포인터를 스마트하게 또는 아닌 값으로 반환하는 대신) 클라이언트로부터 숨겨집니다. 그러나 위임 (인수 검사, 로깅 등) 전에 일부 작업을 수행 할 수 있습니다. –

0

어때?

원래의 operate()가 const가 아닌 참조를 취하기 때문에 단순히 조작 (generators [i]()) 할 수는 없습니다.

#include <iostream> 
#include <string> 
#include <memory> 

class Operand { 
public: 
     Operand(std::string x = "Operand"): x(x) {} 
     const std::string x; 
}; 

class RegisterOperand: public Operand { 
public: 
     RegisterOperand(std::string x = "RegisterOperand") 
       : Operand(x) {} 
}; 

typedef std::auto_ptr<Operand> POperand; 

POperand genOperandA() { return POperand(new Operand("genOperandA")); } 
POperand genOperandB() { return POperand(new Operand("genOperandB")); } 
POperand genOperandC() { return POperand(new RegisterOperand()); } 
// more operand-generation functions 

typedef POperand (*OpGen)(); 

// Table of function pointers 
static const OpGen generators[] = 
{ 
     genOperandA, 
     genOperandB, 
     genOperandC, 
}; 

void operate(const POperand& op) 
{ 
     std::cout << op->x << std::endl; 
} 

int main() 
{ 
     operate(generators[0]()); 
     operate(generators[1]()); 
     operate(generators[2]()); 
     return 0; 
} 
+0

'auto_ptr'의 사용은 C++ 0x에서 더 이상 사용되지 않습니다. 대신에'unique_ptr'을 사용하는 것을 선호하십시오. 아직 C++ 0x에 접근 할 수 없다면'shared_ptr'을 선호합니다. –

+1

@Matthieu : unique_ptr이 매우 마음에 들지만 C++ 0x 언어 기능을 사용하기 때문에 사용하기를 주저합니다. 난 당신이 뭘하는지 알고 shared_ptr의 참조 계산 오버 헤드를 원하지 않는다면 std :: auto_ptr을 사용하는 것이 좋다라고 생각한다. 단지 2 센트. – sellibitze

0

나는이 질문은 얼마 전에 질문을 받았다 알고 있지만 나는 최근에이 문제에 부딪쳤다 자신을 내가 그래도 난 여기에 도움이 될 수있는 다른 솔루션을 함께했다.

그래서 아이디어는 포인터를 관리하는 래퍼를 만드는 것이지만 이동 만 가능한 유일한 포인터와 달리 래퍼를 복사하는 것을 지원합니다.

class PolymorphicType { 
public: 
    /* 
     Class interface ... 
    */ 
    PolymorphicType() { it = nullptr; } 
    virtual ~PolymorphicType() { if(it != nullptr) delete it; }   

    PolymorphicType& operator=(const PolymorphicType& org) { 
      //Clone the derived type and store it 
      if(org.it != nullptr) 
       it = org.it->clone(); 
    } 
private: 
    Base* it; 
}; 

각각의 파생 클래스는 이제 고유 한 복제 방법을 구현해야하며 갈 수 있습니다. 그리고 파생 된 유형의 복제가 어떻게 작동하는지 설명하는 멋진 게시물이 여기 있습니다. Copying derived entities using only base class pointers, (without exhaustive testing!) - C++

희망이 있으면 도움이 될 것입니다.