There’s a class with a parametrized constructor that initializes a member variable. All public methods of the class then use this member variable to do something.
I want to ensure that the caller always creates an object using the parametrized constructor (there is also a setter for this member variable) and then call that object’s methods. In essence, it should be impossible for the caller to call any method without setting a value to the member variable (either by using the parametrized constructor or the setter). Here’s the catch – there is just one method that itself generates a value to be initialized in the member variable (and returns it) – and to call that function, one would need a default constructor.
Currently, a caller can simply make an object using the default constructor and then call that object’s method – I want to avoid checking whether or not the member variable is set in each and every one of the 20-odd methods of the class (and throw an exception if it is not) – except for the one method mentioned above.
Though a runtime solution is acceptable (better than the one I mentioned above); a compile-time solution is preferable so that any developer will not be allowed to make that mistake and then waste hours debuggging it!
Update: Here’s an artist’s impression of the current implementation in code:
class MyClass
{
private:
string m_strProperty;
void InternalNonStaticMethod(int iSomeParam);
public:
MyClass(string strValue)
{
m_strProperty = strValue;
}
MyClass() {}
void setProperty(string strValue)
{
m_strProperty = strValue;
}
string MethodOddManOut()
{
/* Do some computations to generate a value for the property */
string strGeneratedValue("");
InternalNonStaticMethod(4);
/* ... */
return strGeneratedValue; // The value has to be returned and this method cannot simply update the member due to design issues that are beyond the realm of this question
}
void MethodLikeEveryoneElse()
{
/* Do some computation based on the property */
string strTemp = m_strProperty + "EXTEND";
/* If strProperty is empty/garbage then this is going to fail miserably
Trying to avoid the following snippet at 20 other similar methods:
if (!strProperty.empty()) {
strTemp = m_strProperty + "EXTEND";
} else {
throw exception
}
*/
}
void MethodLikeEveryoneElse2()
{
/* Similar to the above method */
}
}
The caller would be a function in some other class using it like this:
void MethodThatUsesThis()
{
MyClass objA;
m_strHandle = objA.MethodOddManOut(); // Save the handle as a member of this object
/* Some other lines of code */
objA.setProperty(strHandle);
objA.MethodLikeEveryoneElse();
}
void AnotherMethodThatUsesThisLater(string strHandle)
{
MyClass objA(strHandle); // The handle that the above method received was passed to this method since they are in different classes
objA.MethodLikeEveryoneElse2();
}
This code snippet is bound to raise tons of allegations on the horrendous design that is being implemented – but my only defense is, this is legacy code (ha! you saw this coming) and I only have the right to change anything in class A (it’s more of an API and a library module) but the caller is not in my jurisdiction.
7
If MethodOddManOut()
does not take arguments, just call it in your default constructor:
class MyClass {
// ...
public:
MyClass() : m_strProperty( MethodOddManOut()) {}
// ...
}
class A {
static const INVALID_PROPERTY_VALUE = -1; //null_ptr for non-primitives?
int property;
public :
explicit A (int initialPropertyValue):
property(initialPropertyValue) {
if (initialPropertyValue == INVALID_PROPERTY_VALUE)
throw illegal_argument("property can't be unset");
}
int setProperty(int newValue) {
if (newValue == INVALID_PROPERTY_VALUE)
throw illegal_argument("property can't be unset");
int rv = property;
property = newValue;
return rv;
}
}
int main() {
A a(56);
a.doSome();
a.setProperty(-1); // fails early, requires no long debug when property is used
a.doNext();
}
1
This is the approache taken to get around the problem (better solutions are still welcome):
Write a private getter for the member in question that validates it’s value and throws an exception. Use this getter in all member functions instead of directly using the member.
private:
hstring GetProperty()
{
if (m_strProperty.empty()) {
throw exception;
} else {
return m_strProperty;
}
}
public:
void MethodLikeEveryoneElse()
{
/* Do some computation based on the property */
string strTemp = GetProperty() + "EXTEND";
/* If strProperty is empty/garbage then this is going to fail miserably
Trying to avoid the following snippet at 20 other similar methods:
if (!strProperty.empty()) {
strTemp = m_strProperty + "EXTEND";
} else {
throw exception
}
*/
}
This is still susceptible to programmer error (some developer may accidentally use the member variable directly) and is a runtime solution rather than a compile-time enforcement.