2011-09-08 2 views
0

C++의 다형성에 문제가 있습니다. 내가 클래스를 초기화하기위한 다소 이상한 구문을 만들려고하지만 그것은 내가 "이"기본 클래스 메서드에서 반환 할 때 새로 만든 된 파생 클래스를 잃어 버리고있어 나타납니다.C++의 기본 클래스에서 파생 된 "this"를 반환하는 다형성

아래의 의사 코드에서 기본 동작을 수행 할 수있는 Base :: initWithPuppies()가 있어야하며이 클래스에서 호출하는 파생 클래스를 반환 할 수 있습니다.

Bar *baz = (new Bar)->initWithPuppies(); 

바람직 템플릿을 사용하고 같은 캐스팅 할 필요없이 :

initWithPuppies<Bar *>(); 

그래, 난 오히려 괴짜 것을 알고

나는이 구문을 갖고 싶어. 그러나 그 이유가 있으며 "우수 사례"가이 상황에 적용되지 않습니다. 이것을 "만약에"이라고 생각하십시오. 아마 당신이 해야할지 :

Bar *baz = new Bar; 
baz->initWithPuppies(); 

전 구문이 필요합니다.

의사 코드 : 편집

class Base 
{ 
    // Kittens 
}; 

class Foo : public Base 
{ 
    public: 
    Base * initWithPuppies(); 
    virtual void test() = 0; 
}; 

Base * Foo::initWithPuppies() 
{ 
    // Call to derived works 
    this->test(); 

    return this; 
} 

class Bar : public Foo 
{ 
    public: 
    void test(); 
}; 

void Bar::test() 
{ 
    std::cout << "It Works!" << std::endl; 
} 

// Preferred syntax 
// This gives "cannot convert from 'Base *' to 'Bar *' " 
Bar *baz = (new Bar)->initWithPuppies(); 

baz->test(); 

/*------------------------------------------*/ 

// This gives " 'test' : is not a member of 'Base' " 
Base *baz = (new Bar)->initWithPuppies(); 

baz->test(); 

/*------------------------------------------*/ 

// This gives "Base is not a polymorphic type" 
UIBar *man = dynamic_cast<UIBar *>((new UIBar)->initWithFrame()); 

baz->test(); 

:

는이 구문이 어떻게 든 가능했던 경우

Bar *baz = (Bar::create())->initWithPuppies(); 

더 나은 것,하지만 난 할 수 없었다 기본 클래스에서 작성하는 방법을 알아내어 타입 캐스팅없이 파생 된 새 인스턴스를 만듭니다.

Bar *baz = (Bar::create<Bar *>())->initWithPuppies(); 

내 대답 :는 니콜 올가미가 정확하지만

(8 시간 동안 내 자신을 대답 할 수없는) 나는 내가 사용하고자하는 구문을 언급 한 바와 같이 당신이 정말로 필요한 경우, 나쁜 관행입니다 내가 않는 한 유사한 구문을 사용하는 (요청하지 않습니다를 ...) 그런 다음이 작업을 수행 할 수 있습니다 : 당신이 유용하게 사용할 수

class Base 
{ 
    // Kittens 
}; 

class Foo : public Base 
{ 
    public: 
    virtual void test() = 0; 
    private: 
    void _initWithPuppies(); 
}; 

void Foo::initWithPuppies() 
{ 
    // Do shit 
} 

class Bar : public Foo 
{ 
    public: 
    Bar * initWithPuppies(); 
    void test(); 
}; 

Bar * Bar::initWithPuppies() 
{ 
    this->_initWithPuppies(); 

    return this;  
} 

void Bar::test() 
{ 
    std::cout << "It Works!" << std::endl; 
} 


Bar *baz = (new Bar)->initWithPuppies(); 

baz->test(); 
+1

호기심에서 실제로'Foo * '를 반환 할 때 함수가'Base *'를 반환하는 이유는 무엇입니까? – templatetypedef

+0

먼저 가상 소멸자를 추가합니다.이 소멸자는 하나의 사례를 제거해야합니다. –

+0

Foo :: initWithPuppies를 호출하고 이것을 반환하는 Bar * Bar :: initWithPuppies를 그냥 오버로드 할 수 없습니까? –

답변

3

뭔가 covariant return types을위한 C++의 지원입니다. 즉, 기본 클래스에서 Base * 유형의 객체를 반환하는 함수를 정의하는 경우 Base* 또는 Base의 파생 클래스에 대한 포인터를 반환하도록 해당 메서드를 재정의 할 수 있습니다. 예를 들어,이 코드는 완전히 합법적입니다.

class Base { 
public: 
    virtual ~Base() {} // Polymorphic classes need virtual destructors! 
    virtual Base* initWithPuppies() = 0; 
} 

class Derived: public Base { 
public: 
    /* Note that the return type is Derived*, but it's still an override! */ 
    virtual Derived* initWithPuppies() { 
     return this; 
    } 
} 

/* Perfectly legal code; Derived::initWithPuppies() returns a Derived* */ 
Derived* d = (new Derived)->initWithPuppies(); 

희망이 있습니다.

+0

'initWithPuppies'는 질문에서 가상이 아니기 때문에 과부하/숨김으로 우리가 잘 해주길 바래요 ;-) –

+0

내가 필요한 구문을 갖도록 하긴하지만 initWithPuppies를 필자의 경우에는 중복되지 않는 클래스이다. 그래도 고마워! – Jay

9

나는이 구문을 갖고 싶어 :

Bar *baz = (new Bar)->initWithPuppies(); 

OK, 바로 거기 중지합니다. 그것은 당신이 원하는 구문이 아닙니다. 생성자는 C++로 존재하는데, 그 이유는 당신이 우회 할 수있는 충분한 이유가 없으면 사용해야합니다.직접 new를 사용하지 않아도, 그것은 개체의 할당 및 초기화를 할 것입니다

Bar *baz = Bar::initWithPuppies(); 

: 당신이 어떤 이유로 생성자를 사용할 수없는 경우

후 공장 기능을 사용 .

오류의 원인은 암시 적으로 상향 변환 할 수 없기 때문입니다. 모든 Bar 개체는 상속의 성격 상 Base 개체입니다. 따라서 C++에서는 파생 클래스에 대한 포인터를 암시 적으로 기본 클래스에 대한 포인터로 변환합니다. 반대로 이 아니요 참 : Base 클래스는 이 아니며이 자동으로 모두 Bar 클래스입니다. 따라서 C++은 상속 계층 구조를 변환하려고 시도한 오류를 정당하게 제공합니다.

이 종류의 변환을 수행하려면 명시 적으로 dynamic_cast을 사용해야합니다. C 스타일의 캐스트 또는 static_cast을 사용할 수는 있지만 이 확실한 경우에만 해당 유형이 인 경우에만 작동합니다.

+0

그래서,'dynamic_cast'를 명시 적으로 사용할 필요는 없습니다. (실제로'Base'에는 가상 함수가 없기 때문에 실제로는 할 수 없습니다.) –

+0

그럼 기본 클래스의 initWithPuppies는 타입 캐스팅없이 새 파생 클래스를 만드는 방법을 알고 있습니까? – Jay

관련 문제