问题
Is there a way in C++ to forbid code to compile if the specific function was not called.
Imagine I have some class:
class CExample
{
public:
void Init();
void DoWork();
};
Is there a way to forbid calling DoWork() if the Init() function was not called for class object?
I want to forbid writing such a code:
CExample e;
e.DoWork();
and permit this version:
CExample e;
e.Init();
e.DoWork();
Can I reach this behaviour somehow with metaprogramming?
回答1:
You can just use a constructor instead of Init
.
In his notes about exception safety in the standard library, as appendix to the 3rd edition of The C++ Programming Language, Bjarne Stroustrup discussed how using init
functions is at odds with the notion of class invariant. It's generally Bad Practice™, mainly for that reason.
Some old GUI frameworks like Microsoft's MFC used init
functions in order to do derived class specific initialization. There are other techniques to do that, including just passing the required information up the construction chain via arguments.
回答2:
No, that would be bad design. If it must be called for the object to be usable, it should be called in the constructor. After an object is constructed, all public methods should be callable-- the object should be fully constructed and ready for use.
回答3:
At compile time it is not known if Init()
has been called before DoWork()
. This can only be decided at runtime. Therefore metaprogramming will not be useful here.
回答4:
You should put your init code into the constructor to enforce that the class is properly constructed. However if you really insist, and your init function really isn't polymorphic you can use CRTP with a protected constructor:
template <typename What>
class InitMe : public What
{
public:
InitMe() : What() { this->Init(); }
};
class CExample
{
public:
void Init() {}
void DoWork() {}
protected:
CExample() {}
};
int main()
{
//CExample e; // Error: protected constructor.
InitMe<CExample> e;
e.DoWork();
}
回答5:
As Cheers and hth. -Alf and Rob K have both touched on, you most definitely want to have your init
work performed in your class constructor. Having to call a separate function to ensure your class is properly ready is poor design.
However, that being said, you can detect if it's been called and act accordingly anyway:
void CExample::Init()
{
// things
...
init = true;
}
void CExample::DoWork()
{
if (!init)
{
Init();
}
}
来源:https://stackoverflow.com/questions/35588622/forbid-code-to-compile-if-some-function-is-not-called