Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function hiding and using-declaration in C++

My confusion comes from "C++ Primer 5th edition" section 13.3, page 518.

Very careful readers may wonder why the using declaration inside swap does not hide the declarations for the HasPtr version of swap.

I tried to read its reference but still did not understand why. Could anyone explain it a little bit please? Thanks. Here is the code sample of the question.

Assume class Foo has a member named h, which has type HasPtr.

void swap(HasPtr &lhs, HasPtr &rhs)
{...}

void swap(Foo &lhs, Foo &rhs)
{
    using std::swap;
    swap(lhs.h, rhs.h);
}

Why swap for HasPtr is not hidden which seems to be declared in outer scope while using std::swap is in the inner scope? Thanks.

like image 406
Sean Avatar asked Feb 22 '17 10:02

Sean


People also ask

What is the use of using declaration?

A using declaration introduces an unqualified name as a synonym for an entity declared elsewhere. It allows a single name from a specific namespace to be used without explicit qualification in the declaration region in which it appears.

What is the use of using in Cpp?

​The using keyword is used to: Bring a specific member from the namespace into the current scope. Bring all members from the namespace into​ the current scope. Bring a base class method ​or variable into the current class's scope.

What is function hiding C++?

In Method Hiding, you can hide the implementation of the methods of a base class from the derived class using the new keyword. Or in other words, in method hiding, you can redefine the method of the base class in the derived class by using the new keyword.

Can a derived class make a public base function private?

You can only change the access specifiers of base members the derived class would normally be able to access. Therefore, you can never change the access specifier of a base member from private to protected or public, because derived classes do not have access to private members of the base class.


2 Answers

Because using std::swap; does not mean "henceforth, every 'swap' should use std::swap", but "bring all overloads of swap from std into the current scope".

In this case, the effect is the same as if you had written using namespace std; inside the function.

like image 200
molbdnilo Avatar answered Sep 30 '22 20:09

molbdnilo


The using-declaration using std::swap does not hide the functions you have declared to swap HasPtr and Foo. It brings the name swap form the std namespace to the declarative region. With that, std::swap can take part in overload resolution.

From the C++11 Standard:

7.3.3 The using declaration

1 A using-declaration introduces a name into the declarative region in which the using-declaration appears.

using-declaration:

using typenameoptnested-name-specifier unqualified-id ;
using :: unqualified-id ;

The member name specified in a using-declaration is declared in the declarative region in which the using-declaration appears. [ Note: Only the specified name is so declared; specifying an enumeration name in a using-declaration does not declare its enumerators in the using-declaration’s declarative region. —end note ] If a using-declaration names a constructor (3.4.3.1), it implicitly declares a set of constructors in the class in which the using-declaration appears (12.9); otherwise the name specified in a using-declaration is a synonym for the name of some entity declared elsewhere.

In your case, you have:

void swap(Foo &lhs, Foo &rhs)
{
    using std::swap;
    swap(lhs.h, rhs.h);
}

The using std::swap; declaration introduces the name swap from the std namespace into the declarative region, which is the body of the swap(Foo&, Foo&) function. The name swap from the global namespace is still accessible in the body of the function.

If what you posted is the entirety of the function, then you don't need the using std::swap declaration. You could get by with just:

void swap(Foo &lhs, Foo &rhs)
{
    swap(lhs.h, rhs.h);
}

since swap(HasPtr &lhs, HasPtr &rhs) is visible from the function.

Now, take a look at the example below.

struct Bar {};

void swap(Bar& lhs, Bar& rhs)
{
}

struct Foo
{
   int a;
   Bar b;
};

void swap(Foo& lhs, Foo& rhs)
{
   swap(lhs.a, rhs.a);  // A problem
   swap(lhs.b, rhs.b);
}

The line marked A problem is a problem since there is no function named swap that can work with two objects of typeint& as argument. You can fix that using one of the following methods:

  1. Use std::swap explicitly.

    void swap(Foo& lhs, Foo& rhs)
    {
       std::swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    
  2. Introduce std::swap in the function.

    void swap(Foo& lhs, Foo& rhs)
    {
       using std::swap;
       swap(lhs.a, rhs.a);
       swap(lhs.b, rhs.b);
    }
    
like image 30
R Sahu Avatar answered Sep 30 '22 21:09

R Sahu