C ++에서 생성자의 주소를 사용할 수없는 이유는 무엇입니까? 똑바로 세우고 직접적으로 희망을 포기할

이것이 언어를 개념적으로 깨뜨릴 특별한 이유가 있거나 기술적으로 실현 불가능한 특정한 이유가 있습니까?

사용법은 새로운 연산자로 이루어집니다.

편집 : 나는 “새로운 운영자”와 “새로운 운영자”를 똑바로 세우고 직접적으로 희망을 포기할 것입니다.

질문의 요점은 왜 생성자가 특별한가 ? 언어 사양에 따라 합법적이지만 반드시 도덕적 인 것은 아니라는 점을 명심하십시오. 합법적 인 것은 일반적으로 나머지 언어와 논리적으로 일치하는 것, 간단하고 간결한 것 및 컴파일러가 구현할 수있는 것에 의해 알 수 있습니다. 이러한 요소들을 평가할 때 표준위원회의 가능한 이론적 근거는 고의적이고 흥미 롭기 때문에 문제입니다.



답변

포인터 대 멤버 함수는 동일한 서명을 가진 멤버 함수가 둘 이상인 경우에만 의미가 있습니다. 그렇지 않으면 포인터에 대해 가능한 값이 하나만 있습니다. 그러나 C ++에서는 동일한 클래스의 다른 생성자가 다른 서명을 가져야하기 때문에 생성자는 불가능합니다.

Stroustrup의 대안은 생성자가 클래스 이름과 다른 이름을 가질 수있는 C ++의 구문을 선택하는 것이었지만 기존의 ctor 구문의 매우 우아한 측면을 막고 언어를 더 복잡하게 만들었습니다. 저에게는 ctor에서 다른 init함수 (포인터-투-멤버가 될 수있는 일반적인 멤버 함수)로 오브젝트의 초기화를 “아웃소싱”하여 쉽게 시뮬레이션 할 수있는 거의 필요한 기능을 허용하지 않는 높은 가격 인 것 같습니다. 만들어진).


답변

생성자는 개체가 아직 없을 때 호출하는 함수이므로 멤버 함수가 될 수 없습니다. 정적 일 수 있습니다.

메모리가 할당 된 후가 완전히 초기화되기 전에 생성자가 실제로 this 포인터로 호출됩니다. 결과적으로 생성자는 여러 특권 기능을 갖습니다.

생성자에 대한 포인터가 있다면 정적 포인터, 팩토리 함수와 같은 것이거나 메모리 할당 직후에 호출되는 무언가에 대한 특수 포인터 여야합니다. 일반적인 멤버 함수일 수 없으며 여전히 생성자로 작동합니다.

염두에 두어야 할 유용한 목적은 새로운 연산자에 전달하여 사용할 생성자를 간접적으로 지정할 수있는 특수한 종류의 포인터입니다. 나는 그것이 유용 할 수는 있지만, 새로운 구문이 필요하고 아마도 대답은 다음과 같습니다. 그들은 그것에 대해 생각했으며 노력할 가치가 없었습니다.

일반적인 초기화 코드를 리팩토링하려면 일반적인 메모리 함수로 충분합니다. 그 중 하나에 대한 포인터를 얻을 수 있습니다.


답변

이는 반환 유형의 생성자가 아니기 때문에 메모리에 생성자를위한 공간을 예약하지 않기 때문입니다. 선언하는 동안 변수가있는 경우처럼 u. 예를 들어 : u가 간단한 변수 X를 쓰면 컴파일러는이의 의미를 이해하지 못하기 때문에 오류를 생성합니다. 그러나 Int x를 쓸 때; 그런 다음 컴파일러는 int type data variable이라는 것을 알게되어 변수를위한 공간을 예약합니다.

결론 :-결론은 반환 유형을 배제하여 주소를 메모리에 얻지 못한다는 결론입니다.


답변

나는 야생 추측을 할 것이다 :

C ++ 생성자와 소멸자는 전혀 함수가 아닙니다 : 매크로입니다. 객체가 생성 된 범위와 객체가 파괴 된 범위에 인라인됩니다. 결과적으로 생성 자나 소멸자가 없으며 객체는 IS입니다.

실제로 클래스의 다른 함수는 함수가 아니라 DONT가 인라인 함수 인 주소 함수를 사용하기 때문에 인라인 함수라고 생각합니다. 함수를 최적화하지 않으면 함수는 주소를 가져 가지 않은 경우에도 “아직있을 것”인 것처럼 보입니다.

C ++ “객체”의 가상 테이블은 JavaScript 객체와는 다릅니다. JavaScript 객체는 생성자를 가져와 런타임시 객체를 통해 객체를 생성 할 수 new XMLHttpRequest.constructor있지만이 객체와의 인터페이스 수단으로 사용되는 익명 함수에 대한 포인터 모음입니다. , 객체 생성 기능 제외. 그리고 객체를 “삭제”하는 것은 의미가 없습니다. 구조체를 삭제하려고하는 것과 같기 때문에 할 수 없습니다. 스택 레이블 일뿐입니다. 다른 레이블에서 원하는대로 쓸 수 있습니다. 클래스를 4 개의 정수로 사용하십시오.

/* i imagine this string gets compiled into a struct, one of which's members happens to be a const char * which is initialized to exactly your string: no function calls are made during construction. */
std::string a = "hello, world";
int *myInt = (int *)(*((void **)&a));
myInt[0] = 3;
myInt[1] = 9;
myInt[2] = 20;
myInt[3] = 300;

메모리 누수가 없으며 문제가 없습니다. 객체 인터페이스와 문자열을 위해 예약 된 많은 스택 공간을 효과적으로 낭비하지만 프로그램을 사용하지 않는 한 프로그램을 파괴하지는 않습니다. 다시 문자열로).

실제로, 이전의 가정이 맞다면 : 문자열의 전체 비용은 32 바이트와 상수 문자열 공간을 저장하는 비용입니다. 함수는 컴파일 타임에만 사용되며 인라인되고 던져 질 수 있습니다. 객체가 생성되고 사용됩니다 (구조체로 작업하고 함수 호출없이 직접 참조하는 경우 함수 점프 대신 중복 호출이 있는지 확인하지만 일반적으로 더 빠르며 공간을 덜 사용합니다). 본질적으로 함수를 호출 할 때마다 언어 디자이너가 설정 한 예외를 제외하고 컴파일러는 해당 호출을 문자로 수행하라는 명령으로 대체합니다.

요약 : C ++ 객체는 무엇인지 모릅니다. 인터페이스와의 인터페이스를위한 모든 도구는 정적으로 인라인되어 런타임시 손실됩니다. 이를 통해 데이터로 구조체를 채우는 것만 큼 효율적으로 클래스를 사용하고 함수를 전혀 호출하지 않고 해당 데이터로 직접 작업 할 수 있습니다 (이 함수는 인라인 됨).

이것은 컴파일러가이 정보를 버릴 수 없으므로 런타임 오버 헤드, 메모리 관리, 구조 호출 비용으로 유형 정보를 동적으로 유지하는 javascript뿐만 아니라 COM / ObjectiveC의 접근 방식과는 완전히 다릅니다. 동적 디스패치 결과적으로 런타임에 프로그램과 “토크 (Talk)”할 수 있으며, 실행 가능한 동안 반영 가능한 구성 요소를 사용하여 프로그램을 개발할 수 있습니다.