Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ namespace collision in copy constructor

I have the following code:

namespace A {     struct Foo {         int a;     }; }  struct Foo {     int b; };  struct Bar : public A::Foo {     Bar(Foo foo) {         c = foo.b;     }     int c; }; 

C++ compilers complains at "c = foo.b" because A::Foo does not have a member named b. If I change the type of Bar parameter with ::Foo it works.

My question is what is the rational behind this behaviour (I suppose it has to do with the fact that the inheritance makes Bar enter the A namespace but I cannot find any documentation to support this theory.

like image 597
Vincent Le Ligeour Avatar asked Nov 28 '19 15:11

Vincent Le Ligeour


People also ask

What is copy constructor in C++?

A copy constructor is a member function which initializes an object using another object of the same class. A copy constructor has the following general function prototype: Following is a simple example of copy constructor. When is copy constructor called? 1. When an object of the class is returned by value. 2.

How do you copy an object in C++?

C++ Copy Constructor 1 Initialize one object from another of the same type. 2 Copy an object to pass it as an argument to a function. 3 Copy an object to return it from a function. More ...

What is the difference between copy constructor and assignment operator?

Copy constructor is called when a new object is created from an existing object, as a copy of the existing object. Assignment operator is called when an already initialized object is assigned a new value from another existing object. In the above example (1) calls copy constructor and (2) calls assignment operator. See this for more details.

What happens if we don’t define our own copy constructor?

If we don’t define our own copy constructor, the C++ compiler creates a default copy constructor for each class which does a member-wise copy between objects. The compiler created copy constructor works fine in general.


1 Answers

Every class has its name injected into it as a member. So you can name A::Foo::Foo. This is called the injected class name.

[class]

2 A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name.

[basic.lookup]

3 The injected-class-name of a class is also considered to be a member of that class for the purposes of name hiding and lookup.

Because unqualified name lookup of the argument type begins in the scope of the class Bar, it will continue into the scope of its base class to account for any member there. And it will find A::Foo::Foo as a type name.

If you want to use the global type name, simply qualify it by its surrounding (global) namespace.

Bar(::Foo foo) {     c = foo.b; } 

Which is doing fully qualified lookup in a scope where the injected class name doesn't appear.

For a followup "why" question see

  • Why is there an injected class name?
like image 120
StoryTeller - Unslander Monica Avatar answered Sep 23 '22 04:09

StoryTeller - Unslander Monica