I was going through a tutorial for building an AST with the help of Clang/LLVM.
I see this syntax there:
struct PPContext {
// Takes ownership of client.
PPContext(clang::DiagnosticClient* client = 0,
const std::string& triple = LLVM_HOSTTRIPLE)
: diagClient(client == 0?new clang::TextDiagnosticPrinter:client),
diags(diagClient),
target(clang::TargetInfo::CreateTargetInfo(triple)),
headers(fm),
pp(diags, opts, *target, sm, headers)
{
// Configure warnings to be similar to what command-line `clang` outputs
// (see tut03).
// XXX: move warning initialization to libDriver
using namespace clang;
diags.setDiagnosticMapping(diag::kind,diag::MAP_IGNORE);
//diag::warn_pp_undef_identifier was the initial value instead of diag::kind. But I changed since it gave error.
}
~PPContext()
{
delete diagClient;
delete target;
}
clang::DiagnosticClient* diagClient;
clang::Diagnostic diags;
clang::LangOptions opts;
clang::TargetInfo* target;
clang::SourceManager sm;
clang::FileManager fm;
clang::HeaderSearch headers;
clang::Preprocessor pp;
};
And:
//What is the constructor doing here ? The construct looks very different and difficult to comprehend !!!
// Could someone break it up for me ?
PPContext(clang::DiagnosticClient* client = 0,
const std::string& triple = LLVM_HOSTTRIPLE)
: diagClient(client == 0?new clang::TextDiagnosticPrinter:client),
diags(diagClient),
target(clang::TargetInfo::CreateTargetInfo(triple)),
headers(fm),
pp(diags, opts, *target, sm, headers)
{
// Configure warnings to be similar to what command-line `clang` outputs
// (see tut03).
// XXX: move warning initialization to libDriver
using namespace clang;
diags.setDiagnosticMapp开发者_StackOverflow社区ing(diag::kind,diag::MAP_IGNORE);
//diag::warn_pp_undef_identifier was the initial value instead of diag::kind. But I changed since it gave error.
}
Please let me know if there is any other material which would be of good help and learning experience. Thanks
These are constructor initializers. They initialized class members with the value given to them. For instance:
class TestClass
{
private:
int someField;
public:
TestClass() : someField(5) { }
};
Will initialize the member someField to have a value of 5 during the call to the TestClass() constructor. You can separate multiple initializers with a ,
to initialize multiple members. You can also pass parameters from the constructor to these initializers such as:
class TestClass
{
private:
int someField;
public:
TestClass(int _someField) : someField(_someField) { }
};
When this constructor is called, the value passed to _someField will be used to initialize someField.
Also consider inheritance. Using the second TestClass
as our base we get the following derived type:
class TestClassDerived : public TestClass
{
public:
TestClassDerived(int _someField) : TestClass(_someField) { }
};
That's how you can construct a base class from a derived type and pass parameters to a non-default constructor. Without this you wouldn't be able to construct the base with the appropriate parameters using a non-default constructor.
It's called a constructor initialization list, which is used for inheritance and initializating member variables. Click this link for a good explanation of this topic.
One scenario this is required is dealing with inheritance. Consider the following:
class Base
{
public:
Base(int n)
{
}
};
class Derived : Base
{
public:
// Error! How do we construct Base? We never pass n
// to the constructor of Base.
Derived(int n)
{
}
};
How can we change the above to compile? With a constructor initialization list:
class Base
{
public:
Base(int n)
{
}
};
class Derived : Base
{
public:
// Now your compiler is happy.
Derived(int n) : Base(n)
{
}
};
This constructur is in the format
PPContext(arg1, arg2)
: initConstructor1,
...,
initConstructor5
where you can exchange initConstructor to the initialization constructors of the PPContext members
精彩评论