C ++에서 함수 내에서 구조와 클래스를 정의 할 수있는 이유는 무엇입니까?
C ++에서 실수로 이와 같은 작업을했는데 작동합니다. 왜 이렇게 할 수 있습니까?
int main(int argc, char** argv) {
struct MyStruct
{
int somevalue;
};
MyStruct s;
s.somevalue = 5;
}
이 일을 한 후, 저는 오래 전에 C ++를위한 가난한 사람의 함수형 프로그래밍 도구로이 트릭에 대해 읽었던 기억이 났지만 이것이 왜 유효한지, 어디서 읽었는지 기억할 수 없습니다.
두 질문에 대한 답변을 환영합니다!
참고 : 질문을 작성할 때이 질문에 대한 참조를 얻지 못했지만 현재 사이드 바에서이를 지적하므로 질문이 다르지만 유용 할 수 있습니다.
[2013 년 4 월 18 일 편집] : 다행히 C ++ 11에서는 아래에 언급 된 제한이 해제되었으므로 로컬에서 정의 된 클래스가 유용합니다! 댓글 작성자 bamboon에게 감사드립니다.
로컬 클래스를 정의 할 수있는 능력 것이다 (AN와 클래스 정의 펑터를 생성하기 operator()()
에 전달하는, 예를 들어 비교 기능을 std::sort()
함께 사용할 수 또는 "루프 기관" std::for_each()
) 훨씬 더 편리.
불행히도 C ++ 는 링크가 없기 때문에 템플릿과 함께 로컬 정의 클래스를 사용하는 것을 금지 합니다. 대부분의 펑터 애플리케이션은 펑터 유형에 템플릿 화 된 템플릿 유형을 포함하기 때문에 로컬로 정의 된 클래스는이를 위해 사용할 수 없습니다. 함수 외부에서 정의해야합니다. :(
[2009 년 1 월 1 일 수정]
표준의 관련 견적은 다음과 같습니다.
14.3.1 / 2 : . 지역 유형, 연결이없는 유형, 명명되지 않은 유형 또는 이러한 유형의 복합 유형은 템플릿 유형 매개 변수에 대한 템플릿 인수로 사용되지 않습니다.
로컬로 정의 된 C ++ 클래스의 한 응용 프로그램은 Factory 디자인 패턴입니다 .
// In some header
class Base
{
public:
virtual ~Base() {}
virtual void DoStuff() = 0;
};
Base* CreateBase( const Param& );
// in some .cpp file
Base* CreateBase( const Params& p )
{
struct Impl: Base
{
virtual void DoStuff() { ... }
};
...
return new Impl;
}
익명 네임 스페이스로도 똑같이 할 수 있습니다.
글쎄요, 기본적으로 왜 안되나요? A struct
in C (시간의 새벽으로 돌아 가기)는 레코드 구조를 선언하는 방법 일뿐입니다. 원하는 경우 간단한 변수를 선언 할 위치에서 선언 할 수없는 이유는 무엇입니까?
일단 그렇게하면 C ++의 목표는 가능하다면 C와 호환되는 것이 었습니다. 그래서 그것은 남았습니다.
실제로 스택 기반 예외 안전 작업을 수행하는 데 매우 유용합니다. 또는 여러 반환 지점이있는 함수에서 일반적인 정리. 이를 종종 RAII (리소스 획득은 초기화) 관용구라고합니다.
void function()
{
struct Cleaner
{
Cleaner()
{
// do some initialization code in here
// maybe start some transaction, or acquire a mutex or something
}
~Cleaner()
{
// do the associated cleanup
// (commit your transaction, release your mutex, etc.)
}
};
Cleaner cleaner();
// Now do something really dangerous
// But you know that even in the case of an uncaught exception,
// ~Cleaner will be called.
// Or alternatively, write some ill-advised code with multiple return points here.
// No matter where you return from the function ~Cleaner will be called.
}
It's mentioned at, for example, section "7.8: Local classes: classes inside functions" of http://www.icce.rug.nl/documents/cplusplus/cplusplus07.html which calls it a "local class" and says it "can be very useful in advanced applications involving inheritance or templates".
It's for making arrays of objects that are properly initialized.
I have a class C which has no default constructor. I want an array of objects of class C. I figure out how I want those objects initialized, then derive a class D from C with a static method which provides the argument for the C in D's default constructor:
#include <iostream>
using namespace std;
class C {
public:
C(int x) : mData(x) {}
int method() { return mData; }
// ...
private:
int mData;
};
void f() {
// Here I am in f. I need an array of 50 C objects starting with C(22)
class D : public C {
public:
D() : C(D::clicker()) {}
private:
// I want my C objects to be initialized with consecutive
// integers, starting at 22.
static int clicker() {
static int current = 22;
return current++;
}
};
D array[50] ;
// Now I will display the object in position 11 to verify it got initialized
// with the right value.
cout << "This should be 33: --> " << array[11].method() << endl;
cout << "sizodf(C): " << sizeof(C) << endl;
cout << "sizeof(D): " << sizeof(D) << endl;
return;
}
int main(int, char **) {
f();
return 0;
}
For the sake of simplicity, this example uses a trivial non-default constructor and a case where the values are known at compile time. It is straightforward to extend this technique to cases where you want an array of objects initialized with values that are known only at runtime.
'program tip' 카테고리의 다른 글
우선 순위 : ETag 또는 Last-Modified HTTP 헤더? (0) | 2020.10.08 |
---|---|
읽기 전용 git 클론을 github에서 forked로 변환하는 방법 (0) | 2020.10.08 |
메모장 ++에 TextFX 메뉴가 없습니다. (0) | 2020.10.08 |
빈 구조체를 확인하는 방법은 무엇입니까? (0) | 2020.10.07 |
원격 브랜치를 추적하기 위해 기존 git 브랜치 가져 오기 (0) | 2020.10.07 |