2010-11-20 2 views

답변

19

C++에는 이와 동일한 기능이 없으므로 Java를 C++로 프로그래밍하려고 시도하는 것은 의미가 없습니다. 즉, 가능한 한 성격 특성과 성향의 많은 부분을 모방하려는 관점에서 접근 할 것입니다. 제가 제안 할 각 방법에는 단점과 한계가 있습니다. 첫 번째 두 개는 실제로 관용적 인 C++가 아니지만 마지막 두 개가 해결 한 문제를 확인하는 것이 중요합니다.

1. C 스타일의 void 포인터.

아무것도가 새로운 배치 새 등 새로운 사업자로부터 무효 포인터에 할당 할 수 있습니다
void* foo = new Foo(); 

항상을 반환 :

나를 가장 기본적이고 최소한 유용, 무효 포인터 시작하자 무효 포인터. 단점은 분명해야합니다 : 지적 된 대상에 관한 유형 정보의 상실. 하나 들어, C + +는 반사 또는 개체를 심문 어떤 수단이 부족합니다. 타입 정보를 머릿 속에 넣고 실제로 사용하기 위해서는 앞뒤로 캐스팅을 사용해야합니다. 무효 포인터로부터 형 변환하는 형에 안전한 방법이 없으므로, 우스꽝 스러움이 계속 될 수 있습니다.

이 함수에서 반환 유형 인 경우 :

void* foo = some_function(_arg0); 

어떻게해야하는지 알아 내야 할 필요가 코드를 사용하는 작가. 불행히도, 종종 어떤 일이 일어나야 만하고, 저자, 당신이 함수에서 반환되어야한다고 생각하는 것이 매우 다릅니다.

2. C 스타일의 조합

대신 java.lang.Object 상위를 처리 할 수있는 무한한 종류의 다음 unions가의 지원 N 타입에 자신을 제한하려면. 이들은 POD 데이터 유형이 인 한 미리 정의 된 값 유형 집합을 동일한 메모리 공간에 보관할 수 있습니다 (). 노동 조합에는 두 가지 매우 중요한 것이 없다 : 할당 된 가치를 알 수있는 능력과 비 POD 유형을 보유 할 수있는 능력. 이것은 std::string과 같은 어떤 종류의 기능을 가진 객체와 함께 사용하도록 완전히 배제합니다.

위가 실제로 무엇을 의미하는지 명확하게 :

union myType{ 
    int a; 
    char b[4]; 
}; 

그때 I 또한 INT의 첫번째 바이트로 설정하고 "MYTYPE"인스턴스의 "B"부분에 제 숯 설정하면 그 같은 가치. C++에서 이것은 정말로 메모리 해킹과 매우 낮은 수준의 프로그래밍에만 유용합니다 (임베디드 등을 생각하십시오.) 그들은 관용적 인 C++가 아닙니다.

3. 부스트 :: 모든

지금, 당신이 진정 원하는 경우 "난 아무것도 저장할 수있는"다음 Boost::Any를 사용합니다. 이것은 매우 유용한 유형 정보를 많이 파괴하지 않고 모든 객체를 유지할 수 있습니다. 부스트 (Boost) 문서는 그 목적이 나보다 훨씬 뛰어납니다.소개 섹션에서 가져온 Any :

템플릿 기반 프로그래밍과는 반반하게 일반 유형이 필요할 때가 있습니다. 실제로 가변적 인 변수는 다른 많은 변수를 수용합니다. C++의 일반적인 strict 및 static 형식보다는 특정 형식을 사용합니다.

생각하면 포함 된 개체에 대한 정보 손실 및 적절한 유형으로 안전하게 캐스팅하는 기능과 같이 void 포인터와 관련된 많은 문제를 해결할 수 있습니다.

4. 부스트 :: 변형

Boost::Variant 객체 정보를 잃지 않고 노동 조합의의 동일한 유형의 문제점을 해결한다. 또한 비 POD 유형 객체와 함께 사용할 수 있습니다. 문서가 가장 잘 상태로 :

일반적인 솔루션은 이후 공통 기본 형식을 통해 조작 된 개체의 동적 할당 기능 (종종 가상 기본 클래스를 Hen01 또는 더 위험, 무효의 *). 구체적인 유형의 객체는 다형 다운 캐스트 구조 (예 : dynamic_cast, boost :: any_cast 등)를 통해 검색 될 수 있습니다.

그러나, 이런 종류의 솔루션은 다음과 같은 이유로 매우 오류가 발생하기 쉬운 있습니다

  1. 다운 캐스트 오류가 컴파일 시간에 감지 할 수 없습니다. 따라서 다운 캐스트 구조의 잘못된 사용은 실행시에만 감지 할 수있는 버그를 발생시킵니다.
  2. 새로운 콘크리트 유형의 추가는 무시할 수 있습니다. 새로운 구체적인 유형이 계층 구조에 추가되면 기존의 다운 캐스트 코드는 새로운 유형을 완전히 무시하고 그대로 작동합니다. 결과적으로 프로그래머는 수 많은 위치에서 수동으로 코드를 찾아 수정해야하기 때문에 종종 런타임 오류가 발생하기 쉽지 않습니다.

편집 : 나는 OP 대답 할 때 무엇을하고 왜 내 생각을 보여 개편

. 나는 또한 아래의 코멘트를 언급했다.

+0

입니다. 구문을 확인해야한다고 생각합니다. –

+0

@Charles Bailey - 네 말이 맞아. 결정된. – wheaties

+1

개인적으로, 나는 이것이 "동등한"것으로 기술 된 주어진 java 코드와 충분히 일치한다고 생각하지 않는다. 자바에서는'Object'에서 안전하게 다른 곳으로 캐스트 할 수 있으며 캐스트가 유효하지 않은 경우 복구 할 수 있습니다. 여러분이 말한 것처럼, C++에서는'void * '에서 동적으로 형변환 할 방법이 없습니다. –

4

Java가 관리되는 힙에서 개체를 할당하므로 C++에서 관리되지 않는 메모리에 개체를 할당하기 때문에 해당 항목이 없습니다. C++은 모든 메모리를 명시 적으로 릴리스해야하지만 Java의 객체는 자동으로 참조 카운트됩니다.

런타임 환경은 근본적으로 다르므로 유사한 모양의 구문으로 인한 유추는 함정입니다.

+0

C++에서 모든 메모리를 명시 적으로 릴리스해야한다는 것은 사실이 아닙니다. C++에서 객체는 자동, 정적 또는 동적 저장 기간을 가질 수 있습니다. 동적 저장 기간이있는 사용자 만 명시 적으로 릴리스해야하며 자동 및 정적 저장 기간이있는 객체의 수명 및 메모리가 자동으로 처리됩니다. 'delete x; '가 명시 적으로 객체를 파괴하고 메모리가 암묵적으로 그 객체의 일부로 해제되었다고 말할 수 있습니다. –

+0

@Charles - 감사합니다. C++의 스택 기반 RAII는 또 다른 예입니다. 내 반응은 질문 ('new X;'를 사용하여 생성 된 객체)의 맥락에서 였고 두 번째 문장에서 C++ 동작의 일반성에 대해 지나치게 독단적입니다. –

10

에 해당하는 은 직접이며 모든 것이 개체가 아니기 때문에 java.lang.Object x = new Foo()과 같습니다. 하지만 을 어떻게 사용 하느냐에 따라Object s 일 때 같은 목표를 달성 할 수 있습니다.

C++에서 java.lang.Object x = new Foo()에 가장 근접한 것은 Abstract Base Classes (ABC)입니다. ABC는 다른 클래스의 기본 클래스로 설계된 클래스입니다.당신은 당신의 클래스 적어도 하나의 pure virtual member function을 제공하여 ABC를 작성하고 당신이이 구문을 사용하여 지정

class Object 
{ 
public: 
    virtual int my_func() = 0; // The "= 0" means "pure virtual" 
}; 

순수 가상 멤버 함수는 일반적으로 기본 클래스에서 구현 된 부분이없는 (각주 참조 * 1). ABC 방송을 사용하려면

int main() 
{ 
    Object obj; // not possible because Object is an ABC 
} 

, 당신은 그것의 서브 클래스를 생성하고 파생 클래스에서 각각의 모든 순수 가상 멤버 함수를 구현해야합니다 :

을 ABC의 인스턴스를 만들 수 없습니다

int main() 
{ 
    Object* my_obj = new Foo; 
} 

일반적인 는 012,389을 부인 : 기본 클래스에 대한 포인터를 가져 오는 동안

class Foo : public Object { public: int my_func() { return 42; } // use of "virtual" is assumed here }; 

지금 당신은, Foo의 인스턴스를 만들 수 있습니다스마트 포인터 등을 사용하는 것에 대한 위의 코드에 적용됩니다. 명확하게하기 위해 이것을 생략했지만, 지금부터는 shared_ptr을 사용할 것입니다.

또한 소멸자와 상식에 대해 slicing

int main() 
{ 
    Foo my_foo; 
    Object& obj_ref = my_foo; // OK 
} 

중요한 메모를 두려워하지 않고 FooObject 참조를 얻을 수 있습니다. ABC를 구현할 때 은 종종에 기본 클래스 (각주 * 2)에 가상 소멸자가 있어야합니다. 기본 클래스에 가상 소멸자를 구현하지 않은 경우 기본 클래스 포인터를 통해 delete 개체를 시도하면 evoke undefined behavior이되며 이는 나쁘다.

class Object 
    { 
    public: 
     virtual int my_func() = 0; 
    }; 
    class Foo : public Object 
    { 
    public: 
     int my_func() { return 42; } 
    }; 

    int main() 
    { 
     Object* obj = new Foo; 
     delete obj; // Undefined Behavior: Object has no virtual destructor 
    } 

는 사실, 상식을 구현하는 내 실제 경험에서 나는 종종 내가 정말 가상 순수 할 멤버 함수가 소멸자는 사실을 알게 될 것입니다. 내가 디자인 한 ABC에는 종종 순수하지 않고 하나의 가상 소멸자 인 많은 가상 메소드가 있습니다. IMO (논쟁의 여지가 있음), 이것은 ABC를 디자인 할 때 좋은 시작점입니다. dtor를 순수하게 만들고 기본 클래스에 최소한의 비 순수 가상 멤버 함수를 유지하고 기본의 순수 가상 dtor에 대한 구현을 제공합니다 수업. 이런 방식으로 설계하면 실제 코드에서 수행 할 수없는 작업을 찾을 수 있습니다.이 작업은 설계에서 벗어난 것입니다.


각주 :


* 1)베이스 클래스 기본 클래스에서 순수 가상 멤버 함수에 대한 정의를 제공 할 수있다. 그러나 이것이 표준이 아니며,이를 수행 할 수있는 이유는이 게시물의 범위를 벗어납니다. 이 작업을 수행 할 때 표준에 선언과 함께 정의를 제공하지 않을 수도 있다는 특별 규칙이 있습니다. 그들은 분리되어 있어야합니다. 이와 같이 :

* 2) 가상 소멸자에 대한 규칙에는 예외가 있습니다. 이 기사의 범위를 벗어나지 만 더 나은 경험 법칙은 "A base class destructor should be either public and virtual, or protected and nonvirtual"

+0

당신은 "지금부터는'shared_ptr'을 사용 하겠지만 당신은 그렇게하지 않습니다. –

관련 문제