2

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.

  • 11
    The usual solution is to make the default constructor private or not to have one at all. Do you need something more complicated? – Kilian Foth Nov 11 '13 at 11:10
  • 12
    If you absolutely need something to be initialized for the object to function, why on earth are you offering constructors which don't initialize this? – Phoshi Nov 11 '13 at 11:52
  • Something else to ask yourself: why are you offering a way to set the variable outside of the constructor if it needs to be initialized anyway? – jzx Nov 11 '13 at 15:18
  • If you provide a constructor a default one will not be automatically generated for you. I'm not sure what you're worried about. – bstamour Nov 13 '13 at 21:26
  • 1
    I thought about what KilianFoth said - Oops! Sorry I forgot an important detail - there is just one method that itself generates a value to be initialized in the member variable - and to call that function, one would need a default constructor. You would say, make that method static! Can't - that calls another non-static private method (that would just lead to a domino effect). – dotbugfix Nov 16 '13 at 18:10
1

If MethodOddManOut() does not take arguments, just call it in your default constructor:

class MyClass {
     // ...
     public:

     MyClass() : m_strProperty( MethodOddManOut()) {}

     // ...
}
-1
   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
    I've added a code snippet explaining the situation to the question. One of the reasons I cannot use this answer is that I need to use the default constructor, without setting a value to the member, for one of the methods that doesn't need to property but generates it instead. – dotbugfix Nov 17 '13 at 7:38
-2

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.