Click here to Skip to main content
15,867,453 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Is the following really an error, as VS indicates? I thought that even with no overrides, a derived class could look up the name of a virtual function correctly defined in the base class. Yes, there is a function with the same name in both classes, but I thought name lookup worked on function signature.
C++
#include <iostream>

class BaseItem {
   public:
      virtual std::string str() { return "Hello World"; }
   };

class DerivedItem : public BaseItem {
   private:
      std::string strC;
   public:
      void str(std::string s) { strC = s; }
   };

int main() {
   DerivedItem item;
   std::string str = item.str(); //Error. C2660: func doesn't take 0 args.
   std::string str2 = item.BaseItem::str(); //OK.
   }


What I have tried:

Running it. The line following works, but I see no real reason for specifying the lookup directly.
Posted
Updated 19-Jul-20 16:22pm

This... is very interesting. I don't use C++ a ton but found these:
Unqualified name lookup - cppreference.com[^]
Argument-dependent lookup - cppreference.com[^] : Check out the "Details" section.
Dominance (C++) - Wikipedia[^]

You are correct. The unqualified name lookup shadows/hides based on names, not signatures which would include the arguments. Only situations where the unqualified lookup produces no results is argument-dependent lookup used.
 
Share this answer
 
Comments
David O'Neil 14-Jul-20 3:30am    
Thanks! CPallini found the exact reason, but I '5'd this for the info!
virtual function specifier - cppreference.com[^]:
A function with the same name but different parameter list does not override the base function of the same name, but hides it: when unqualified name lookup examines the scope of the derived class, the lookup finds the declaration and does not examine the base class.

Adding
C++
virtual std::string str() override { return BaseItem::str(); }
to your derived class would make your program compile.
 
Share this answer
 
Comments
David O'Neil 14-Jul-20 3:28am    
Thank you. That's what I was looking for. Did not know name lookups were restricted this way, so learned something new tonight!
Jon McKee 14-Jul-20 3:38am    
Yea, this was a really good question. I learned something as well :)
CPallini 14-Jul-20 3:34am    
"so learned something new tonight!"
So did I (this morning) :-)
Stefan_Lang 14-Jul-20 4:52am    
And so did I - didn't expect to learn something so basic after decades of programming in C++!

Have a 5.
Jon McKee 14-Jul-20 3:36am    
EDIT: Nvm, I get what you mean now CPallini. By adding the override in the derived you allow overloading to properly take place again since both functions are in the same scope.
Hi,

A bit late to the party - but here goes:

There is a simple solution : add using BaseItem::str; to the public section of DerivedItem, like this

class DerivedItem : public BaseItem
{
private:
    std::string strC;
public:
    using BaseItem::str;
    void str( std::string s ) { strC = s; }
};

This will expose all definitions of str from BaseItem, regardless of signature, from DerivedItem.

Best regards
Espen Harlinn
 
Share this answer
 
Comments
David O'Neil 19-Jul-20 22:56pm    
Thanks! Great addition to the conversation!
I think the reason it is an error is because str is not virtual. The derived class has an non-virtual str method and it takes an argument. Since you didn't pass one it is an error. If you do give it an argument as is, I think you will get another error saying a void function can not return anything.
 
Share this answer
 
Comments
David O'Neil 14-Jul-20 3:15am    
You are correct that giving it an argument gives an error for the other reason. It is also interesting that making the derived class's 'str' function virtual doesn't fix the issue, but gives another 'doesn't take 0 args'. The only two ways to fix it is 1) as I did in the original example, 2) create a virtual function in the DerivedItem class that just returns the BaseItem function. Kinda ugly. I thought C++ name lookups were more powerful than this, but then again, I've never faced this situation before.
There are two simple errors in your code:
C++
std::string str = item.str(); //Error. C2660: func doesn't take 0 args.

1. DerivedItem::str requires a string as its parameter, you cannot omit that.
2. It is declared void so it does not return any result.

Change those two and it works.
 
Share this answer
 
Comments
David O'Neil 14-Jul-20 3:45am    
The question was why isn't C++ capable of determining that the BaseItem 'str' function matches the requirement. I thought it should be able to.
Richard MacCutchan 14-Jul-20 4:22am    
The issue is simply that you are making a direct call to DerivedItem::str with the wrong syntax. There is no requirement to call the base class at that point, since the derived function overrides it. If you were calling it through a pointer then things might be different. There is a (not unreasonable) description at Virtual Functions | Microsoft Docs[^].

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900