2012-07-21 3 views
1

저는 현재 C++ 서적을 읽을 것입니다. 클래스를 가리킬 때 약간 혼란 스럽습니다. 이전 책에C++ 클래스를 가리키는 중

의 예는이 방법으로 클래스와 메소드를 사용 :

그러나
Calculator myCalc; 
myCalc.launch(); 

while(myCalc.run()){ 
    myCalc.readInput(); 
    myCalc.writeOutput(); 
} 

가, 지금은 그것을 이런 식으로 일에 변경된 :

Calculator* myCalc = new Calculator; 
myCalc -> launch(); 

while(myCalc -> run()){ 
    myCalc -> readInput(); 
    myCalc -> writeOutput(); 
} 

를 내가 수없는 것 이 방법으로 왜 그런지 설명해주십시오.

표준 방법을 사용하는 대신이 방법으로 클래스를 가리키는 이유는 무엇입니까?

차이점은 무엇입니까? 그리고 어떤 상황이 어느 것이 바람직할까요?

감사합니다.

+0

책이 '삭제'됩니까? – chris

+3

용어가 약간 틀립니다. 클래스, 객체 또는 클래스의 인스턴스를 가리 키지 않습니다. – juanchopanza

+0

@chris 내가 볼 수있는 한 멀리는 아닙니다. 매우 간단한 예일 뿐이지 만 세부적인 것은 아닙니다. –

답변

7

첫째, 당신은 클래스를 가리키는 것이 아니라, 클래스의 인스턴스에, 또한 객체을했다. (클래스를 가리키는 것은 C++에서는 불가능합니다. 당신이 나에게 묻는다면 그 결함 중 하나입니다).

차이점은 개체가 할당 된 위치입니다. 당신이하고있는 경우 :

Calculator myCalc; 

전체 개체가 stack에 생성됩니다. 스택은 로컬 변수, 중첩 호출 등을위한 저장소이며 일반적으로 1MB 이하로 제한됩니다. 반면에 메모리 관리자 호출이 필요 없으므로 스택에 대한 할당이 빠릅니다.

당신이 할 경우 :

Calculator *myCalc; 

많이하지가 Pointer가 스택에 할당 된 것을 제외하고 발생합니다. 포인터는 일반적으로 크기가 4 또는 8 바이트 (32 비트 대 64 비트 아키텍처)이며 메모리 주소 만 보유합니다. 귀하의 예에 표시된 것처럼 또 하나 개의 라인으로 결합 할 수 있습니다

myCalc = new Calculator; 

: 당신은 객체를 할당하고 같은 일을하여 포인터 지점을 확인해야합니다.여기에서 객체는 대략 에 할당되어 있습니다 (스왑 공간 및 아키텍처 제한은 고려하지 않은 상태로 유지). 따라서 더 많은 데이터를 저장할 수 있습니다. 하지만 메모리 관리자가 킥을 가져와 객체의 힙에 여분의 공간을 찾거나 운영 체제에서 더 많은 메모리를 가져와야 할 필요가 있기 때문에 속도가 느립니다. 이제 포인터 myCalc에 개체의 메모리 주소가 포함되어 있으므로 *-> 연산자와 함께 사용할 수 있습니다.

스택의 객체에 대한 포인터 또는 참조를 전달할 수 없습니다. 범위가 끝나면 (예 : 함수의 끝에서) 스택이 정리되어 객체를 사용할 수 없으므로 스택 외부에서 객체를 지울 수 없습니다.

오, 언급하는 것을 거의 잊었습니다.

그래서
delete myCalc; 

그것을 요약하기 : 당신이 * 같은 수동으로 삭제해야하므로 힙에 객체가 자동으로 파괴되지 않습니다 자신의 범위를 떠날 수없는 작은, 짧은 생활 오브젝트를 들어, 당신이 사용할 수있는 스택을 기반으로하는 할당이지만, 크고 긴 살아있는 객체의 경우 일반적으로 힙이 더 좋은 곳입니다.


* : 이상적으로는 그렇지 않습니다. std::unique_ptr과 같은 스마트 포인터를 사용하십시오.

+0

포인터는 16 바이트, 128 바이트 수 있습니다. – Linuxios

+0

@Linuxios는 현재 아키텍처에 없습니다.)), "보통"을 추가하겠습니다. –

+3

@Linuxios : 할머니가 강철 와이어를 가지고 있다면 우산이라고 부를 수 있습니다. 여기서 실용적으로 토론을 너무 일반적인 것으로 만들어서 혼란에 빠지게하지 마세요. IMHO. –

1

둘 다 표준입니다. 하나는 다른 하나보다 선호되지 않습니다.

첫 번째 매개 변수는 좁은 범위에서 선언하고 사용하는 일반적인 지역 변수입니다.

포인터 방법을 사용하면 동적으로 메모리를 할당하고 포인터 유형에 할당 할 수 있습니다. 그것은 "별표"표기법의 의미입니다. 이것들은 메소드 밖으로 전달되거나 메소드가 종료 된 후에 살면서 멤버 변수에 할당 될 수 있습니다.

하지만 포인터가 가리키는 개체를 다 마쳤을 때도 메모리를 정리해야한다는 사실을 알고 있어야합니다. 그렇지 않으면 결국 많은 사람들이 "메모리 누수"가있는 장기 실행 응용 프로그램을 소모합니다.

1

변수가 클래스의 인스턴스 또는 참조 인 경우 점 (.)을 사용하고 변수가 클래스 인스턴스에 대한 포인터 인 경우 ->를 사용합니다.

1

이들은 모두 C++ 표준의 일부이지만 핵심 차이점이 있습니다. 첫 번째 방법으로 객체는 스택에 저장됩니다 (함수 및 로컬 변수가 저장되고 더 이상 사용되지 않으면 제거됩니다). 변수 유형을 포인터로 선언하면 스택에 포인터 만 저장되고 객체 자체는 힙으로 이동합니다.

스택 로컬 변수를 사용하여 메모리를 할당하면 C++에서 자동으로 처리됩니다. 힙에있을 때는 new으로 메모리를 가져와 delete으로 해제해야합니다.

스택 예제에서 코드는 .을 사용하여 메서드를 호출하고 포인터에서 메서드를 호출하면 C++에서 *obj.method()과 동일한 바로 가기 ->을 제공합니다.

new을 사용할 때는 항상 use delete입니다.

0

변수 myCalc의 수명이 매우 긴 경우 한 사용이됩니다. new이 필요한 경우 생성하고 delete을 입력하면 제거 할 수 있습니다. 그렇다면 필요하지 않을 때 주변을 운반하는 것에 대해 걱정할 필요가 없으며 공간 만 차지합니다. 또는 필요할 때 언제든지 다시 초기화 할 수 있습니다.

매우 큰 클래스가있는 경우 new을 사용하여 스택이 아닌 힙에 할당하는 것이 일반적입니다. 스택 공간이 부족하고 힙 크기가 커지기 때문에 남은 부분이므로 힙 공간이 더 쌉니다.

또는 물론 동적 배열을 할당하는 가장 일반적인 용도입니다. myCalc = new Calculator[x]; 새 계산기를 x 만들 수 있습니다. x이 얼마나 큰지 미리 알지 못하는 경우 정적 변수를 사용하여이 작업을 수행 할 수 없습니다. 얼마나 많은 객체를 만들지.

0

표기법/구문의 명백한 차이 외에도. 포인터는 일반적으로 데이터를 함수에 전달할 때 유용합니다.두 번째 복사본 계산기 이루어질 필요하므로

void myFunc(Calculator c) { 
    ... 
} 

위에

void myFunc(Calculator *c) { 
    ... 
} 

보통 바람직하다. 포인터는 가리키는 위치 만 포함하므로 데이터 자체를 포함하지 않고 메모리의 다른 지점을 나타냅니다. 또 다른 좋은 사용은 문자열에 대한 텍스트 파일을 읽고 텍스트를 처리하는 함수를 호출한다고 상상해보십시오. 각 함수는 포인터가 아닌 경우 문자열의 복사본을 만듭니다. 포인터는 기계 구조에 따라 4 또는 8 바이트이므로 기능에 전달할 때 많은 시간과 메모리를 절약 할 수 있습니다.

어떤 경우에는 사본으로 작업하는 것이 더 나을지도 모르지만. 어쩌면 당신은 단지 포인터에 대한 중요한 것들을 너무

Calculator myFunc(Calculator c) { 
    ... 
} 

처럼 변형 된 버전을 반환 할 것은 "새로운"키워드입니다. 포인터를 만드는 유일한 방법은 아니지만 C++에서 가장 쉬운 방법입니다. 또한 malloc()이라는 함수를 사용할 수 있어야하지만 struct와 c IMO에서는 더 많은 기능을 제공하지만 두 가지 방법을 모두 보았습니다.

말하기 C. 포인터는 배열에도 유용 할 수 있습니다. 난 당신이 여전히 컴파일 시간에 배열의 크기를 선언 할 수있는 것 같아요 + +,하지만 나는 오해 될 수 있습니다. 당신은 다음과 같은 것을 사용할 수 있습니다.

Calculator *c; 
.... 
Calculator d = c[index]; 

이제는 모호한 IMO가 될 수있는 배열이 있습니다.

나는 내가 아는 모든 것에 관해서 다룰 것이며, 제공된 예제에서 당신이 제공 한 2 개의 미리보기 간에는 차이가 없다고 생각합니다.

0

우선, 클래스를 가리 키지 않고 클래스의 인스턴스 (또는 객체)를 가리키고 있습니다. 다른 언어에서는 클래스도 실제로는 객체입니다. :-)

예제는 그 예입니다. 대부분 포인터를 사용하지 않을 가능성이 높습니다.

이제 포인터 란 무엇입니까? 포인터는 실제 물건을 가리키는 작은 작은 물건입니다. 초인종에있는 이름표와 마찬가지로 - 이름이 표시되지만 사실은 당신이 아닙니다. 그러나, 그것은 당신이 아니기 때문에, 당신은 실제로 다른 위치에 당신의 이름으로 여러 버튼을 가질 수 있습니다.

포인터를 사용하는 한 가지 이유가 있습니다. 하나의 개체가 있지만 여러 위치에서 해당 개체에 대한 포인터를 유지하려는 경우입니다. 내 말은, 실제 세계에는 온갖 종류의 장소에서 당신에게 수 많은 "포인터"가 있다는 것입니다. 프로그램이 데이터 내에서 비슷한 일을 필요로한다고 상상하는 것이 너무 어렵지 않아야합니다.

포인터는 개체를 복사해야하는 번거 로움을 피하기 위해 사용되며 값 비싼 작업이 될 수 있습니다. 함수에 포인터를 전달하는 것이 훨씬 저렴합니다. 또한 함수를 사용하여 객체를 수정할 수 있습니다 (기술적으로 C++ "참조"는 포인터이기도하지만 좀 더 명확하지 않으며 제한적입니다).

또한 "new"로 할당 된 개체는 "delete"로 할당이 해제 될 때까지 계속 남아 있습니다. 따라서 스코프에 의존하지 않고 주위의 기능이 끝나면 사라지지 않으며 길을 잃을 때 사라집니다.

플러스, 어떻게 과일과 함께 가방을 만들겠습니까? "bag"객체를 할당합니다.그런 다음 "과일"객체를 할당하고 가방 객체 안에 포인터를 설정하여 과일 객체를 가리키면 가방에 해당 열매가 포함되어 있음을 나타냅니다. 과일도 가방 객체에 대한 포인터를 얻을 수 있습니다. 단지 과일에서 작업하는 코드도 가방에 들어갈 수 있습니다. 또 다른 "과일"오브젝트를 할당하고 포인터 체인을 설정할 수 있습니다. 각 "과일"에는 "다음"과일을 가리키는 단일 "다음"포인터가있을 수 있으므로 임의의 수의 과일을 가방에 넣을 수 있습니다 : 가방에는 첫 번째 과일에 대한 포인터가 들어 있으며 각 과일에는 다른 과일에 대한 포인터가 있습니다. 그래서 당신은 과일의 전체 사슬을 얻습니다. (이것은 단순한 "컨테이너"이며 임의의 수의 객체를 "포함하는"클래스가 여러 개 있습니다).

실제로 포인터가 사용되는시기와 이유를 설명하는 것은 그렇게 간단하지 않습니다. 일반적으로 필요할 때가있을 것입니다. 이러한 상황에 처했을 때 유용성을 확인하는 것이 훨씬 쉽습니다. "우산이 왜 유용한 지"와 같이 - 일단 비를 쏟으면 우산의 유용성이 분명해질 것입니다.

관련 문제