2011-11-03 2 views
1

다음 방법이 a) 법적 및 b) 도덕인지 묻는 중입니다. 저는 C++ 03에 중점을두고 질문하지만 C++ 11에 대한 노트도 환영합니다. 아이디어는 바보 같은 B::B(int foo) : A(foo) {} 생성자를 구현하는 데있어 기본 구성이 가능한 파생 클래스를 막는 것입니다.게재 위치가 새로 변경된 진정한 기본 클래스 구조

class Base { 
    private: 
    int i; 
    Base(int i) : i(i) {} 
    protected: 
    Base() {} 
    public: 
    static Base* create(int i); 
}; 
class Derived : public Base { 
}; 

Base* Base::create(int i) { 
    Derived* d = new Derived(); 
    Base* b = static_cast<Base*>(d); 
    delete b; 
    new(b) Base(i); 
    return d; 
} 

내게 말하고 싶은 것은, 뭔가 비린내가 있습니다. 어떤 Derived 클래스가 해당 생성자의 Base 멤버에 액세스하는 경우, 다른 어딘가에 있고 싶습니다. 그렇지 않은 경우 접근법이 나쁜 이유를 확인하는 데 문제가 있습니다.

어쨌든 이것이 받아 들일 수있는 접근 방법이라고 생각되면 참조 회원을 처리하는 방법은 무엇입니까 (int& Base::j과 같은)?

참고 : 이것은 How can I fake constructor inheritance in C++03?의 후속 질문입니다.


편집 : 질문을 게시 할 때 내가 정신이되어 있어야합니다. 물론 delete b 대신에 나는 b->~Base()을 의미했습니다. 나는 낮은 혈당을 비난했다!

답변

3

코드가 잘못되어 정의되지 않은 동작이 트리거됩니다. Base 클래스에는 가상 소멸자가 없으므로 delete b은 정의되지 않은 동작을 발생시킵니다.

그렇지 릴리스 파생 된 자원 (코드의 목적이 될 것 같다, 아야!), 사실에가 시도 할 것이다 것을는 사실에서 delete 범위에 대한 호출에서 UB 이유 두 객체의 레이아웃에 따라 작동 여부에 관계없이 할당 된 메모리를 해제합니다. 메모리가 할당 해제에 실패하면 배치가 성공하면 다음 줄의 새 호출은 이미 해제 된 메모리의 객체를 초기화하려고 시도합니다.

코드를 변경 한 경우에도 에) 해제 문제를 피하려고 : 더 delete 및 정의되지 않은 동작의 특정 소스가 사라진 것을 따라서 이없는 경우

Base* Base::create(int i) { 
    Derived *d = new Derived; 
    Base * b = static_cast<Base*>(d); 
    b->~Base();      // destruct, do not deallocate 
    new (b) Base(i); 
    return d; 
} 

코드는 아마) 언급하는 너무 많은 방법으로 정의되지 않은 동작은 (아직도있다. 일단 소멸자에 대한 호출이 아직 UB 인 경우에도 Base 유형을 다시 작성한다는 사실은 해당 객체에 대한 동적 디스패치가 Derived 객체가 아닌 Base 객체로 간주 될 수 있음을 의미합니다 (이 경우 vtable의의, 실행시의 형태 정보를 가리키는 vptr 오히려

) Derived보다 Base를 참조합니다 그리고 잘못 될 수있는 두 개 또는 세 개의 다른 것들 아마 거기에 내가 ...

지금 생각할 수 없다
+0

하나가 있다면'~ 파생 '을 부를 것입니다.'delete b'라고 말하면 제가 원하지 않는 것입니다. – bitmask

+0

@bitmask : 원하는 것은 중요하지 않습니다 ... 기본 클래스에 가상 소멸자가 없으면 언어에서 기본 클래스에 대한 포인터를 삭제할 수 없습니다. –

+0

@bitmask : 모든 것을 논의하는 접근법에는 너무 많은 것들이 잘못되었지만, 예를 들어 메모리 할당/할당 해제, 각 시점에서의 객체의 런타임 유형 등에 대해 생각해야합니다. –

1

delete b은 단지 Base 소멸자를 호출 할뿐만 아니라 메모리 반환을 할당 해제합니다. new에 의해 편집되고 destructor [Base에 가상 소멸자가 있다고 가정하면 ... 가상이 아닌 것으로 의도 한 경우 동작은 단순히 [정의되지 않음]으로 시작합니다.]즉, 이후에 새로운 배치를 사용하면 더 이상 유효하지 않은 새로운 Base 객체가 메모리에 생성되고 이전에 파괴 한 부분 인 Derived을 절대 대체하지 않을 것입니다. 간단히 말해, 올바른 행동을 취하는 것조차하지 못했습니다.

솔직히 말해서 나는 당신이 무엇을하려하는지 보지 못했습니다 ... 왜 그냥 Derived을 인수를 전달하는 대신에 기본 구성해야합니까? 바보가 아니라, 일이 끝나는 길입니다.

+0

네, 무슨 뜻인지 알아요. 때로는 더 나은 것을 만들어 내고 그것을 더 심하게 만들려고 노력합니다. 되풀이되는 패턴입니다. – bitmask