Reputation: 5090
Inspired by this question, I'd like to know whether there is any trick (like SFINAE) to achieve the opposite.
Edit: Adding example
I have something like this (it is very simplified because it has a lot of details):
#include <iostream>
class Base {
public:
Base(){}
virtual ~Base(){
}
void initialize() { implementation(); }
private:
virtual void implementation() = 0;
};
class Derived : public Base {
private:
virtual void implementation() { std::cout << "initialization" << std::endl;}
};
int main() {
std::unique_ptr<Base> b(new Derived());
b->initialize();
return 0;
}
The initialize method must be called.
But if I put initialize method inside Base constructor it will call a pure virtual method. I want to know if there is a way to prevent someone to use improperly the constructed object.
Edit: My "solution":
#include <iostream>
class Base {
public:
virtual ~Base(){
}
Base() {};
private:
void initialize() { implementation(); }
virtual void implementation() = 0;
template<class DerivedType> friend Base *factory();
};
class Derived : public Base {
private:
Derived() {}
virtual void implementation() { std::cout << "initialization" << std::endl;}
template<class DerivedType> friend Base *factory();
};
template<class DerivedType>
static Base *factory(){
Base *b = new DerivedType();
b->initialize();
return b;
}
int main() {
std::unique_ptr<Base> b(factory<Derived>());
return 0;
}
Upvotes: 2
Views: 1203
Reputation: 20818
Note that this should not be required because when you create an object, that object can initialize itself properly without having to call an initialization function.
This may sound strange, but in most cases that initialization()
function is not proper:
class A
{
public:
A() { do initialization of A fields here; }
};
class B : public A
{
public:
B() { do initialization of B fields here; }
};
That should be sufficient in most cases.
If you pass a parameter to the constructor, you may need some interfaces (to not create loops in your #include) and then you just pass those parameters around as in:
class C;
class D;
class A
{
public:
A(C c) { do initialization of A fields here; }
};
class B : public A
{
public:
B(C c, D d) : A(c) { do initialization of B fields here; }
};
Otherwise, to verify at run time, boost and my controlled_vars (templates to make types such as int safe, finally!) offer facilities to check whether a field was initialized and it can either throw and return a default value.
I'm otherwise not aware of any facility in the compiler to do such a test. However, if you write a test (you should always have tests anyway!) then your test can do such verifications.
Note that I first thought of a profiler, but that requires a test which will anyway tell you whether you are correct or not and the profiler could show you that the initialization was called, but you wouldn't know whether that happened in all cases.
However, to really enforce such initialization at compile time (assuming you really need it), as mentioned by Ed S., the best is probably to use a factory. That way all the ugly initialization code remains hidden.
Upvotes: 1
Reputation: 124790
You can't force a compiler error, but there are other alternatives.
If an instance of your type is simply invalid unless initialize is called, and if documenting that fact or throwing an exception upon use if uninitialized is unacceptable, then you should make the constructor private and expose a static method to create instances of your type.
This way clients of your code simply cannot use an uninitialized instance of your type. If there is a better, more elegant approach I don't know of it (but maybe someone around here does).
Upvotes: 2