Optional function parameters: Use default arguments (NULL) or overload the function?

前端 未结 12 1497
情书的邮戳
情书的邮戳 2020-12-08 00:44

I have a function that processes a given vector, but may also create such a vector itself if it is not given.

I see two design choices for such a case, where a func

相关标签:
12条回答
  • 2020-12-08 01:01

    I would favour a third option: Separate into two functions, but do not overload.

    Overloads, by nature, are less usable. They require the user to become aware of two options and figure out what the difference between them is, and if they're so inclined, to also check the documentation or the code to ensure which is which.

    I would have one function that takes the parameter, and one that is called "createVectorAndFoo" or something like that (obviously naming becomes easier with real problems).

    While this violates the "two responsibilities for function" rule (and gives it a long name), I believe this is preferable when your function really does do two things (create vector and foo it).

    0 讨论(0)
  • 2020-12-08 01:01

    The first way is poorer because you cannot tell if you accidentally passed in NULL or if it was done on purpose... if it was an accident then you have likely caused a bug.

    With the second one you can test (assert, whatever) for NULL and handle it appropriately.

    0 讨论(0)
  • 2020-12-08 01:02

    I, too, prefer the second one. While there are not much difference between the two, you are basically using the functionality of the primary method in the foo(int i) overload and the primary overload would work perfectly without caring about existence of lack of the other one, so there is more separation of concerns in the overload version.

    0 讨论(0)
  • 2020-12-08 01:09

    I usually avoid the first case. Note that those two functions are different in what they do. One of them fills a vector with some data. The other doesn't (just accept the data from the caller). I tend to name differently functions that actually do different things. In fact, even as you write them, they are two functions:

    • foo_default (or just foo)
    • foo_with_values

    At least I find this distinction cleaner in the long therm, and for the occasional library/functions user.

    0 讨论(0)
  • 2020-12-08 01:09

    I'm squarely in the "overload" camp. Others have added specifics about your actual code example but I wanted to add what I feel are the benefits of using overloads versus defaults for the general case.

    • Any parameter can be "defaulted"
    • No gotcha if an overriding function uses a different value for its default.
    • It's not necessary to add "hacky" constructors to existing types in order to allow them to have default.
    • Output parameters can be defaulted without needing to use pointers or hacky global objects.

    To put some code examples on each:

    Any parameter can be defaulted:

    class A {}; class B {}; class C {};
    
    void foo (A const &, B const &, C const &);
    
    inline void foo (A const & a, C const & c)
    {
      foo (a, B (), c);    // 'B' defaulted
    }
    

    No danger of overriding functions having different values for the default:

    class A {
    public:
      virtual void foo (int i = 0);
    };
    
    class B : public A {
    public:
      virtual void foo (int i = 100);
    };
    
    
    void bar (A & a)
    {
      a.foo ();           // Always uses '0', no matter of dynamic type of 'a'
    }
    

    It's not necessary to add "hacky" constructors to existing types in order to allow them to be defaulted:

    struct POD {
      int i;
      int j;
    };
    
    void foo (POD p);     // Adding default (other than {0, 0})
                          // would require constructor to be added
    inline void foo ()
    {
      POD p = { 1, 2 };
      foo (p);
    }
    

    Output parameters can be defaulted without needing to use pointers or hacky global objects:

    void foo (int i, int & j);  // Default requires global "dummy" 
                                // or 'j' should be pointer.
    inline void foo (int i)
    {
      int j;
      foo (i, j);
    }
    

    The only exception to the rule re overloading versus defaults is for constructors where it's currently not possible for a constructor to forward to another. (I believe C++ 0x will solve that though).

    0 讨论(0)
  • 2020-12-08 01:11

    I would definitely favour the 2nd approach of overloaded methods.

    The first approach (optional parameters) blurs the definition of the method as it no longer has a single well-defined purpose. This in turn increases the complexity of the code, making it more difficult for someone not familiar with it to understand it.

    With the second approach (overloaded methods), each method has a clear purpose. Each method is well-structured and cohesive. Some additional notes:

    • If there's code which needs to be duplicated into both methods, this can be extracted out into a separate method and each overloaded method could call this external method.
    • I would go a step further and name each method differently to indicate the differences between the methods. This will make the code more self-documenting.
    0 讨论(0)
提交回复
热议问题