Explain this

K

Kalle Rutanen

Hello

Here is a short code snippet which does not compile. Could someone
explain why this is ?

class A
{
public:
void set(int a)
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A
{
public:
void set(int a, int b)
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);
return 0;
}
 
B

Bob Hairgrove

Hello

Here is a short code snippet which does not compile. Could someone
explain why this is ?

class A
{
public:
void set(int a)
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A
{
public:
void set(int a, int b)
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);
return 0;
}

Is this homework?
 
M

Mike Wahler

Kalle Rutanen said:
Hello

Here is a short code snippet which does not compile. Could someone
explain why this is ?

class A
{
public:
void set(int a)
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A
{
public:
void set(int a, int b)

Takes two arguments.
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);

You only gave one argument.
return 0;
}

My compiler's error message makes the problem very clear:

error C2660: 'set' : function does not take 1 parameters

-Mike
 
A

Alf P. Steinbach

* Kalle Rutanen:
Here is a short code snippet which does not compile. Could someone
explain why this is ?

class A
{
public:
void set(int a)
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A
{
public:
void set(int a, int b)
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);
return 0;
}

The declaration of B::set hides the base class A::set.

You can add

using A::set;

in class B.
 
D

Dan Platt

Kalle said:
Hello

Here is a short code snippet which does not compile. Could someone
explain why this is ?

class A
{
public:
void set(int a)
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A
{
public:
void set(int a, int b)
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);
return 0;
}

Alternatively, you could call b.A::set(2) in main() [SOME compilers used
to be quite clear that the derived class definition HID the base class
definition if the arguments were different.]

Dan
 
K

Kalle Rutanen

The declaration of B::set hides the base class A::set.
You can add

using A::set;

in class B.

Having read a reference C++ book, I noticed that this is due to name
lookup. Compilers first look for the matching name in class hierarchy
and then try to match parameters.

Your solution of using "using" is what I needed, thank you;)

As a theoretical question: Why do you think they (the C++ standard
committee) made the decision (in this inheritance situation) to hide
functions by name rather than "normally" by name and parameters (it
seems a bit unlogical) ?
 
K

Kalle Rutanen

Alternatively, you could call b.A::set(2) in main() [SOME compilers used
to be quite clear that the derived class definition HID the base class
definition if the arguments were different.]

Thank you. As a reply, please see the reply I posted to Alf P. Steinbach
to avoid repeating;)
 
K

Kalle Rutanen

class A
Takes one argument.
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A

Inherits the one-argument set from A.
{
public:
void set(int a, int b)

Takes two arguments.
{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);

You only gave one argument.

...but B contains also the one-argument set inherited from A.

Anyway, thanks for the effort, and please see the reply I posted to Alf.
P Steinbach to avoid repeating;)
 
J

Jerry Coffin

As a theoretical question: Why do you think they (the C++ standard
committee) made the decision (in this inheritance situation) to hide
functions by name rather than "normally" by name and parameters (it
seems a bit unlogical) ?

Doing otherwise would have been inconsistent with the rest of the name
lookup rules. Just for example:

char x;

void f() {
int x;

x = 'a';
}

At least in C and C++, the fact that we're assigning a char to x
doesn't mean that the assignment is really to the global x. The x that
is visible inside the function is the one that's defined inside of the
function, and the type we're assigning doesn't change that.

If this was changed, it would also cause a serious difference between C
and C++ in a different way: in C, a character literal has type int,
where in C++ it has type char. As such, if the name lookup was done
this way, compiling this as C would assign to the local variable, but
compiling it as C++ would assign to the global.

Changing this rule also makes lot of code relatively fragile. For
example:

class X {
int f(int);

int g() { f('a'); }
}

I _know_ that X::g() calls X::f(), implicitly casting the char to an
int before doing so. Some would argue that this implicit conversion is
undesirable, but at least I know what's going to happen -- and since
it's widening a char to an int, the conversion is fairly safe.

Consider what happens if the function signature worked across block
scopes though: if there was a global function f(char), it would get
called in preference to X::f().

While these problems may be less obvious when inheritance is involved,
I think there would be serious problems there as well. Consider, for
example:

class base {
void utility(char);
};

class derived : public base {

void utility(int);

void g() {
utility('a');
};

Now, in this case it seems likely that the programmer _intended_ to
call derived::utility -- in fact, he might not be consciously aware
that the base class even contains a function by that name (since it's
private, he shouldn't have to be). Unfortunately, he's passing a char
instead of an int, so if base::utility was visible it would be the
better match (and since it's not accessible, the code wouldn't
compile).

In this particular case, that could be "cured" by changing that rule as
well, so that 'private' functions would be invisible rather than
inaccessible in a derived class.

Knowing how things go, however, there are almost certainly a few other
things that depend on that rule being the way it is -- and each of them
undoubtedly has a few more dependencies, and so on. You could
undoubtedly create a coherent language with these things changed, but
the result wouldn't be a C++ that was marginally different in one
particular area, but a language that was considerably different
throughout.

Compiling this language would be considerably more difficult -- in
fact, compiling ordinary code would become somewhat similar to
compiling an exported template with the current language, and for much
the same reason: the meaning of a particular name wouldn't be defined
entirely by the code itself, but by the entire context within which the
code was used. Likewise, many of the surprising things that can arise
with two-phase name lookup in an exported template could then affect
non-template code as well. Rather than being able to read and
understand code in small, digestible chunks, you'd have to read and
(sort of) undertand all the context before any one piece could be
understood.
 
M

Mike Wahler

Kalle Rutanen said:
Takes one argument.
{
v[0] = a;
v[1] = a;
}
int v[2];
};

class B: public A

Inherits the one-argument set from A.
Takes two arguments.

... and since the signature is different, but the name
is the same, hides the 'set' from 'A'.

{
v[0] = a;
v[1] = b;
}
};

int main()
{
B b;
b.set(2);

You only gave one argument.

..but B contains also the one-argument set inherited from A.

... and you hid it by giveing a different function the same name.

This is C++, not 'hide and seek'. :)

-Mike
 
K

Kalle Rutanen

Jerry said:
Doing otherwise would have been inconsistent with the rest of the name
lookup rules. Just for example:

Thank you for an excellent explanation!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,278
Latest member
BuzzDefenderpro

Latest Threads

Top