7

I recently discovered a new application of the using keyword; not with reference to the namespace functionality but inside a derived class declaration. In my case this was pertinent in regards the issues surrounding the 'operator=' member-function.

I had a situation where, given the declarations:

class CString{
public:
    ...//Various functions.
    operator=(const CString &cString)
    {
        //code to share internal array and increment reference count
    }
    operator=(const wchar_t *pstrString)
    {
        //code to create a personal internal array,
        //resize it appropriately and copy the pstrString argument.
    }
    ...
};

class CStringEx : public CString{
    ...//various members that expand upon CString's abilities.
};

...an object of CStringEx did not work as I expected:

CStringEx cString;

cString=L"String contents";

Instead a compiler error was generated stating 'CStringEx has no 'operator=()' function that takes an argument of type wchar_t*' (or - very close - words to that effect). After quite a bit of study I learned this is because even the automatically compiler-generated operator= member-functions of a derived class override those inherited from its parent class. This seems counter-intuitive and user-UNfriendly to me.

However, if I add a using keyword:

class CStringEx : public CString{
public:
    using CString::operator=;
    ...
};

...the child class will now use its parent's operator= member function and all is well.

So far, so good. However, after further reading here and elsewhere I have learned that many programmers do not like to utilize using for this purpose. For instance I have read some commentators who describe potentially unwanted side-effects, such as brining in ALL the operator= from the parent. However, again, other than in very specific circumstances I do not understand why inheriting all the parent member-functions would be and issue. If this is the major concern could someone explain the general dangers of doing so?

The only alternative I can think of is to write out stub functions in the child class for every operator= member-function of it's parent and then explicitly call those respective member-functions:

class CStringEx : public CString{
public:
    ...
    const CStringEx& operator=(const wchar_t* pstrString)
    {
        CString::operator=(pstrString);
        return *this;
    }
    const CStringEx& operator=(const CString &cString)
    {
        CString::operator=(cString);
        return *this;
    }
    ...//and so on...
};

When compared to the version with using CString::operator= this looks extremely ugly, cumbersome and messy to me. So again, why not use the using keyword?

  • 5
    "I have learned that many programmers do not like to utilize using for this purpose." Nonsense. If it's the right tool, it's the right tool. – John Dibling Oct 30 '14 at 17:33
  • "I do not understand why. Could someone explain the dangers of doing so?" Presumably whatever reasoning you left out of your question might allude to this. –  Oct 30 '14 at 17:36
  • Woah... That's a little ascerbic remyable! But, okay; you mean the reasoning of those who don't like using __using__? If so then, for example [link]http://stackoverflow.com/questions/4122214/why-operator-doesnt-get-inherited-from-a-template-class[/link] and _David Rodríguez_ comments. To clarify; I do not understand why the situation he describes would be 'bad' and a reason to use the stub-function approach instead. There are other examples of similar discouragement for _using_ in that post and others. –  Oct 30 '14 at 17:41
  • @Gemman Not at all. Your question is fine as it is, but it doesn't hurt to bring in those specific viewpoints (it's easier than proving a negative.) –  Oct 30 '14 at 17:42
  • No worries - I see what you mean. I'll edit my original question to be a little more specific. –  Oct 30 '14 at 17:44
  • Anyway, that specific question you linked, it appears the disadvantage is that [it's all or nothing](https://stackoverflow.com/questions/6997194/using-declarations-and-const-overloads). You can't bring in specific overloads. –  Oct 30 '14 at 17:50
  • Ahh... I suppose that might cause issues if you only want access to a very specific operator from amongst a larger clutch. In that case I suppose my question is - does `using` override not only compiler-generated functions but also explicitly declared ones in the child class? I can certainly appreciate **that** being a problem also!!! –  Oct 30 '14 at 17:54

1 Answers1

1

This is a bit subjective so let's review what we know:

If using is the right tool for the job, then you should use it. That said:

  • using will always bring in all the parent methods/operators, even newly added ones that you never intended. This might even result in broken code when someone creates a parent assignment operator that doesn't interact well with the child object.
  • Bringing in the parent's copy assignment operator means you can create a CStringEx from a CString but perhaps this is intended behavior.
  • Future readers/maintainers may not be familiar with the operator using syntax and may make the code slightly harder to grok.

Given the fact that you're questioning it originally (based on things you've heard) and the points above, let's step back and look at your design a moment. The CStringEx has two possibilities:

  1. It has additional data members. In this case I'm willing to assert that inheriting parent operators is going to do something wrong in some or all cases, since the child class members won't be handled in the assignment.
  2. It does not have additional data members, it only provides additional code functionality. In this case, please don't be tempted to use a child class. Instead write free-function algorithms that operate on either (iterator) ranges or, if you must, CString objects.
Mark B
  • 95,107
  • 10
  • 109
  • 188
  • **VERY**, very well put Mark!!! I am a little uncomfortable with the idea of using external functions rather than a child class - but I think I understand the dangers you outline. What you describe sounds very similar to how the Hewlett Packard STL functions operate with external algorithms and so forth that 'clip on' to and mesh with a number of different object types. As yet I have not learned or become familiar with these new ideas - but it is certainly something to look at in future. I have nonetheless written an iterator so the string will function with the new `for(:)` ranged loop. –  Oct 30 '14 at 19:39