元對象編譯器
moc
程序用於處理
Qt 的 C++ 擴展
.
The
moc
工具讀取 C++ 頭文件。若找到一個或多個類聲明包含
Q_OBJECT
macro, it produces a C++ source file containing the meta-object code for those classes. Among other things, meta-object code is required for the signals and slots mechanism, the run-time type information, and the dynamic property system.
The C++ source file generated by
moc
must be compiled and linked with the implementation of the class.
Both
qmake
and
CMake
generate makefiles with build rules that will invoke
moc
accordingly, so you will not need to use the
moc
直接。
qmake
will add these build rules by default, whereas with CMake, you can use the
AUTOMOC
property to handle
moc
automatically. For more background information on
moc
,見
Qt 為什麼將 MOC 用於信號/槽?
moc
is typically used with an input file containing class declarations like this:
class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = 0); ~MyClass(); signals: void mySignal(); public slots: void mySlot(); };
In addition to the signals and slots shown above,
moc
also implements object properties as in the next example. The
Q_PROPERTY
() macro declares an object property, while
Q_ENUM
() declares a list of enumeration types within the class to be usable inside the
特性係統
.
In the following example, we declare a property of the enumeration type
優先級
that is also called
priority
and has a get function
priority()
and a set function
setPriority()
.
class MyClass : public QObject { Q_OBJECT Q_PROPERTY(Priority priority READ priority WRITE setPriority) Q_ENUMS(Priority) public: enum Priority { High, Low, VeryHigh, VeryLow }; MyClass(QObject *parent = 0); ~MyClass(); void setPriority(Priority priority) { m_priority = priority; } Priority priority() const { return m_priority; } private: Priority m_priority; };
The Q_FLAGS() macro declares enums that are to be used as flags, i.e. OR'd together. Another macro, Q_CLASSINFO (), allows you to attach additional name/value pairs to the class's meta-object:
class MyClass : public QObject { Q_OBJECT Q_CLASSINFO("Author", "Oscar Peterson") Q_CLASSINFO("Status", "Active") public: MyClass(QObject *parent = 0); ~MyClass(); };
The output produced by
moc
must be compiled and linked, just like the other C++ code in your program; otherwise, the build will fail in the final link phase. If you use
qmake
, this is done automatically. Whenever
qmake
is run, it parses the project's header files and generates make rules to invoke
moc
for those files that contain a
Q_OBJECT
macro. Similarly, when setting
AUTOMOC
to
ON
, CMake will scan the header and source files at build time and invoke
moc
accordingly.
If the class declaration is found in the file
myclass.h
, the moc output should be put in a file called
moc_myclass.cpp
. This file should then be compiled as usual, resulting in an object file, e.g.,
moc_myclass.obj
on Windows. This object should then be included in the list of object files that are linked together in the final building phase of the program.
moc
For anything but the simplest test programs, it is recommended that you automate running the
moc
. By adding some rules to your program's makefile,
make
can take care of running moc when necessary and handling the moc output.
可以使用
CMake
or
qmake
to generate makefiles that does all the necessary
moc
處理。
If you want to create your makefiles yourself, here are some tips on how to include moc handling.
For Q_OBJECT class declarations in header files, here is a useful makefile rule if you only use GNU make:
moc_%.cpp: %.h moc $(DEFINES) $(INCPATH) $< -o $@
If you want to write portably, you can use individual rules of the following form:
moc_foo.cpp: foo.h moc $(DEFINES) $(INCPATH) $< -o $@
You must also remember to add
moc_foo.cpp
to your
SOURCES
(substitute your favorite name) variable and
moc_foo.o
or
moc_foo.obj
to your
OBJECTS
變量。
Both examples assume that
$(DEFINES)
and
$(INCPATH)
expand to the define and include path options that are passed to the C++ compiler. These are required by
moc
to preprocess the source files.
While we prefer to name our C++ source files
.cpp
, you can use any other extension, such as
.C
,
.cc
,
.CC
,
.cxx
,和
.c++
, if you prefer.
For
Q_OBJECT
class declarations in implementation (
.cpp
) files, we suggest a makefile rule like this:
foo.o: foo.moc foo.moc: foo.cpp moc $(DEFINES) $(INCPATH) -i $< -o $@
This guarantees that make will run the moc before it compiles
foo.cpp
. You can then put
#include "foo.moc"
at the end of
foo.cpp
, where all the classes declared in that file are fully known.
這裏是 moc 支持的命令行選項:
| 選項 | 描述 |
|---|---|
-o<file>
|
寫入輸齣到
<file>
而不是到標準輸齣。
|
-f[<file>]
|
Force the generation of an
#include
statement in the output. This is the default for header files whose extension starts with
H
or
h
. This option is useful if you have header files that do not follow the standard naming conventions. The
<file>
part is optional.
|
-i
|
Do not generate an
#include
statement in the output. This may be used to run the moc on on a C++ file containing one or more class declarations. You should then
#include
the meta-object code in the
.cpp
文件。
|
-nw
|
不生成任何警告 (不推薦)。 |
-p<path>
|
Makes the moc prepend
<path>/
to the file name in the generated
#include
語句。
|
-I<dir>
|
添加 dir 添加到 Header (頭) 文件的 include 路徑。 |
-E
|
Preprocess only; do not generate meta-object code. |
-D<macro>[=<def>]
|
定義宏采用可選定義。 |
-U<macro>
|
Undefine 宏。 |
-M<key=value>
|
Append additional meta data to plugins. If a class has Q_PLUGIN_METADATA specified, the key-value pair will be added to its meta data. This will end up in the Json object that gets resolved for the plugin at run time (accessible from QPluginLoader ). This argument is typically used for tagging static plugins with information resolved by the build system. |
@<file>
|
Read additional command-line options from
<file>
. Each line of the file is treated as a single option. Empty lines are ignored. Note that this option is not supported within the options file itself (i.e. an options file can't "include" another file).
|
-h
|
顯示用法和選項列錶。 |
-v
|
顯示
moc
的版本號。
|
-Fdir
|
macOS. Add the framework directory
dir
to the head of the list of directories to be searched for header files. These directories are interleaved with those specified by -I options and are scanned in a left-to-right order (see the manpage for gcc). Normally, use -F /Library/Frameworks/
|
You can explicitly tell the moc not to parse parts of a header file.
moc
defines the preprocessor symbol
Q_MOC_RUN
. Any code surrounded by
#ifndef Q_MOC_RUN ... #endif
moc
will warn you about a number of dangerous or illegal constructs in the
Q_OBJECT
類聲明。
If you get linkage errors in the final building phase of your program, saying that
YourClass::className()
is undefined or that
YourClass
lacks a vtable, something has been done wrong. Most often, you have forgotten to compile or
#include
the moc-generated C++ code, or (in the former case) include that object file in the link command. If you use
qmake
, try rerunning it to update your makefile. This should do the trick.
moc
does not handle all of C++. The main problem is that class templates cannot have the
Q_OBJECT
macro. Here is an example:
class SomeTemplate<int> : public QFrame { Q_OBJECT ... signals: void mySignal(int); };
The following constructs are illegal. All of them have alternatives which we think are usually better, so removing these limitations is not a high priority for us.
若正使用多繼承,
moc
assumes that the first inherited class is a subclass of
QObject
. Also, be sure that only the first inherited class is a
QObject
.
// correct class SomeClass : public QObject, public OtherClass { ... };
虛擬繼承采用 QObject is not 被支持。
In most cases where you would consider using function pointers as signal or slot parameters, we think inheritance is a better alternative. Here is an example of illegal syntax:
class SomeClass : public QObject { Q_OBJECT public slots: void apply(void (*apply)(List *, void *), char *); // WRONG };
You can work around this restriction like this:
typedef void (*ApplyFunction)(List *, void *); class SomeClass : public QObject { Q_OBJECT public slots: void apply(ApplyFunction, char *); };
It may sometimes be even better to replace the function pointer with inheritance and virtual functions.
當校驗其自變量的簽名時, QObject::connect () 會逐字比較數據類型。因此, Alignment and Qt::Alignment are treated as two distinct types. To work around this limitation, make sure to fully qualify the data types when declaring signals and slots, and when establishing connections. For example:
class MyClass : public QObject { Q_OBJECT enum Error { ConnectionRefused, RemoteHostClosed, UnknownError }; signals: void stateChanged(MyClass::Error error); };
這裏是令人不快構造的範例:
class A { public: class B { Q_OBJECT public slots: // WRONG void b(); }; };
Signals and slots can have return types, but signals or slots returning references will be treated as returning void.
signals
and
slots
類區間
moc
will complain if you try to put other constructs in the
signals
or
slots
sections of a class than signals and slots.