나는 Qt를 배우고 있으며, 신호 슬롯 패턴으로 많은 즐거움을 얻고있다. 내가 가지고있는 질문은 시그널과 슬롯이 이벤트 청취자와 핸들러를위한 단순한 구문 설탕인가 아니면 백그라운드에서 일어나는 일이 다른 성격인가라는 것입니다. 나중에, 근본적인 차이점은 무엇입니까?신호와 슬롯은 구문상의 설탕입니까? 아니면 그들에게 더 많은 것이 있습니까?
답변
신호와 슬롯 문법 설탕이 있습니까하거나 더이? 내가 가진 문제는 신호와 슬롯 단순히 이벤트 리스너에 대한 문법 설탕/핸들러
없음
, 자신의 존재에 대한 평균 이유 가 배출 및 처리의 감 결합되어있는 점이다.또는 무엇 백그라운드에서 발생하는 서로 다른 성격입니까?
아이디어는 특정 "이벤트"처리에서 방출을 분리한다는 것입니다. 직접 함수 호출을 대안으로 생각한다면, 배출과 관련된 코드가 실제로 "신호"를 처리하는 코드를 알아야 할 필요가 있다는 점을 지적하고 싶습니다. 그것은 두 부분이 너무 너무 빡빡하게 될 것입니다.
은 동적 신호 발광을 담당하는 코드를 변경하지 않고 다른 신호 처리기를 추가하는 것이 가능하지 않을 것이다. 이 같은 예를 상상해
는코드의 일부는 신호
이 코드는 직접 "세척 과일"방법을 부를 것 "과일이 도착"방출한다.
과일 수를 계산하는 방법을 추가하려는 경우 어떻게해야합니까?
- 이전 코드는 해당 메서드에 대한 직접 호출을 포함하도록 수정해야합니다.
신호 슬롯 메커니즘을 사용하면 원래 코드를 건드릴 필요가 없습니다. 새로운 슬롯을 완전히 다른 코드의 기존 신호에 간단하게 연결할 수 있습니다. 이것은 좋은 디자인과 자유라고합니다. 당신이 사전에 Qt는 응용 프로그램에 대해 모르고 주위의 모든 신호를 방출 할 수 Qt는 같은 라이브러리가있을 때
이 특히 유용합니다. Qt 애플리케이션은 신호를 처리하는 방법을 스스로 결정합니다.
또한이 패턴은 방향 함수 호출의 경우와 같이 응용 프로그램의 응답 성을 높이고 차단을 줄입니다. 이는 Qt 신호 슬롯 메커니즘이 구축 된 이벤트 루프가 있기 때문입니다. 당연히 직접 호출과 함께 스레딩을 사용할 수도 있지만 이상적인 세계에서 필요한 것보다 훨씬 더 많은 작업과 유지 관리가 필요합니다.
부분적으로 이미 만져지는 것처럼 "직접 호출"을 실행할 수도 있지만 백그라운드에서 QtEventLoop이 처리를 위해 이러한 이벤트를 큐에 넣습니다.
실제로 내부 구현 코드는 moc (메타 오브젝트 컴파일러)에서 찾을 수 있습니다. Moc는 몸체를 정의하지 않는 신호를위한 함수를 기본적으로 생성하기 때문에 필요할 때 QObject 서브 클래스에 선언하면됩니다.
당신은 여기에서 주제에 따라 자세한 내용을보실 수 있습니다,하지만 난 내 설명이 당신이 가야 수 있다고 생각 :
QtDD13 - Olivier Goffart - Signals and Slots in Qt 5
이것은 단지 문법 설탕이 아니다. Qt 신호/슬롯의 배경에는 실제 작업이 있습니다. 이 작업은 MOC (Meta-Object Compiler)에 의해 수행됩니다. 이것이 Q_OBJECT 매크로를 가진 클래스를 포함하고있는 모든 C++ 헤더 파일에 대한 프로세스가있는 이유입니다. 당신이 멀티 스레딩 컨텍스트에있을 때
신호/슬롯의 "어려운 부분"입니다. 송신자와 이미 터가 동일한 스레드 내에없는 경우 실제로 :: Qt는 단일 스레드 환경에서 직접 접속이다() 함수의 ConnectionType 인자 (예를 들어, 함수의 직접 호출), A의 대기. 이 경우 신호는 Qt 이벤트 루프에 의해 처리되어야합니다. 자세한 내용은
신호와 슬롯은 메소드 호출을 호출 된 메소드와 분리하는 방법입니다. 그들은 C++ 언어에 새로운 구문을 추가하지 않았기 때문에 문법적으로 설탕을 전혀 사용하지 않습니다. 신호 방출은 메서드 호출입니다. 슬롯은 일반 오래된 인스턴스 메소드입니다. 두 코드를 연결하는 코드는 평범한 오래된 C++입니다. 새로운 것은 없습니다 - 어떤 종류의 설탕도 없습니다.
는 "구문 설탕"이라고 부르는 대부분의 의견에 가깝다 - 그 빈을 정의 (Q_SLOT
는, Q_SIGNAL
, signals
, slots
)는 메타 오브젝트 컴파일러 (MOC)에 의한 처리 방법을 표시하는 데 사용됩니다. Moc은 선언의 일반적인 C++ 구문을 기반으로하는 내부 정보 및 신호 구현을 생성합니다 (일부 제한 사항 포함).
moc은 일반 C++를 이해하고 구문 설탕이 아닌 일반적인 인스턴스 메소드 선언을 기반으로하는 내성 데이터를 생성하기 때문에 이것은 구문 설탕이 아니라고 주장합니다. "설탕"은 클래스 선언에에 대한 메타 데이터를 생성하는 데있어 조기 비관적 인 회피를 피할 수 있습니다. 또한 moc는 메소드 정의를 무시할 수 있습니다. 그렇지 않으면 구문 분석이 필요하며 정의가없는 메소드는 신호라고 가정합니다.
emit
매크로는 사람이 섭취하기위한 것으로 메소드 호출이 실제로 신호 방출이라는 표시 일뿐입니다. 그것은 moc에서 사용하지 않습니다. 그것은 비어있는 것으로 정의됩니다.
Q_OBJECT
및 Q_GADGET
매크로는 메타 데이터에 액세스하는 데 사용되는 일부 클래스 멤버를 선언합니다. 논쟁의 여지가 있지만 몇 줄의 선언을 입력하지 않아도되므로 실제 "설탕"의 유일한 부분입니다.
잠재적으로 코드가 작동하도록 만드는 코드가 상당히 있습니다.
신호 :
구현 MOC 의해 생성 된 인스턴스 메소드이다
그 이름과 인자에 대한 완전한 내성 정보를 갖는다. 이 인스턴스는
QMetaMethod
의 인스턴스로 제공됩니다.
슬롯 :
는 구현이 당신이 제공하는 인스턴스 메서드,
유사하게 전체 성찰의 정보를 가지고있다.
메타 정보가 런타임 가능하며 열거하고 는 신호의 서명이나 슬롯의 사전 지식이없는 코드 사용될 수
.신호를 내 보내면 moc에서 생성 한 메서드를 호출하기 만하면됩니다. 이 메서드는 관련 뮤텍스를 가져오고, 첨부 된 슬롯 목록을 반복하며, 호출을 실행하여 필요에 따라 추가 뮤텍스를 획득하는 Qt 라이브러리 코드를 호출합니다. 송신자와 수신자가 서로 다른 스레드에 상주 할 수 있기 때문에이를 올바르게 처리해야합니다. 하나는 존재하지 않는 객체에 대한 슬롯 호출 전달을 피해야합니다. 아, 교착 상태도 원하지 않아요. 이것은 약간의 사전 고려가 필요합니다.
신호와 슬롯이 모두 유일한 방법이기 때문에 신호를 다른 신호에 확실히 연결할 수 있습니다. 기본 메커니즘은 호출되는 신호를 신경 쓰지 않고 단지 호출 할 수있는 방법 일뿐입니다. invokable 메소드는 메타 데이터가없는 메소드입니다.
관련 신호가 방출되면 슬롯이 호출됩니다. 신호 방출은 생성 된 신호 본체에 대한 메소드 호출 일뿐입니다. 슬롯 호출은 즉시 (소위 직접 연결) 또는 이벤트 루프 (지연 대기 연결)로 지연 될 수 있기 때문에 이벤트 리스너 패턴과는 다릅니다. 대기열 슬롯 호출은 인수를 복사하여 QMetaCallEvent
에 묶음으로써 구현됩니다. 이 이벤트는 QObject::event
에 의해 메소드 호출로 "변환"됩니다. 이것은 이벤트 루프가 이벤트를 대상 객체에 전달할 때 발생합니다.
메타 데이터에는 단순한 신호 및 슬롯 서명이 포함됩니다. 또한 신호/슬롯 매개 변수 유형을 기본 및 복사 구성 할 수 있습니다. 이는 대기중인 호출을 구현하는 데 필요합니다. 또한 열거 형에 대한 키 - 값 쌍이 포함되어있어 Qt가 쉽게 스크립트 할 수 있습니다. Qt 메서드에 전달 된 모든 enum 값은 런타임에 이름순으로 조회 할 수 있습니다!
이것은 신호와 슬롯의 이유를 설명하지 못하기 때문에 질문에 대답하지 않습니다. 그것은 기본적으로 작동에 관해서 만 쓰지만 이유는 아닙니다. OP 질문은 그 이유에 관한 것입니다. – lpapp