Polymorphism and inheritance

  • Thread starter Bart Friederichs
  • Start date
B

Bart Friederichs

Hello,

I created the following inheritance:

class Parent {
public:
void foo(int i);
};

class Child : public Parent {
public:
void foo(int i, int i);
};

The following code fragment does not work (it doesn't compile, g++
complains about 'no matching function call for Child::foo(int)':

....
Child c;
int k = 0;
c.foo(k);
....

I assumed that by inheriting the base class, the 'Child' class would
have two 'foo' methods, with different parameters. Apparently not. Adding

void foo(int i) { Parent::foo(i); }

to the Child class, fixes it, but is that how it should be done? Why is
the Parent's foo() not polymorphised-inherited by Child?

TIA,
Bart
 
T

Thomas J. Gritzan

Bart said:
Hello,

I created the following inheritance:

class Parent {
public:
void foo(int i);
};

class Child : public Parent {
public:
void foo(int i, int i);
};

The following code fragment does not work (it doesn't compile, g++
complains about 'no matching function call for Child::foo(int)':
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

...
Child c;
int k = 0;
c.foo(k);
...

I assumed that by inheriting the base class, the 'Child' class would
have two 'foo' methods, with different parameters. Apparently not. Adding

void foo(int i) { Parent::foo(i); }

to the Child class, fixes it, but is that how it should be done? Why is
the Parent's foo() not polymorphised-inherited by Child?

The compiler only looked in the derived class for functions with name
"foo", found one and stopped. You have to tell it that there are more
functions of the same name, for example with a "using" declaration.
 
T

Thomas J. Gritzan

Bart said:
Hello,

I created the following inheritance:

class Parent {
public:
void foo(int i);
};

class Child : public Parent {
public:
void foo(int i, int i);
};

The following code fragment does not work (it doesn't compile, g++
complains about 'no matching function call for Child::foo(int)':
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

...
Child c;
int k = 0;
c.foo(k);
...

I assumed that by inheriting the base class, the 'Child' class would
have two 'foo' methods, with different parameters. Apparently not. Adding

void foo(int i) { Parent::foo(i); }

to the Child class, fixes it, but is that how it should be done? Why is
the Parent's foo() not polymorphised-inherited by Child?

The compiler only looked in the derived class for functions with name
"foo", found one and stopped. You have to tell it that there are more
functions of the same name, for example with a "using" declaration.
 
N

newbarker

Hello,

I created the following inheritance:

class Parent {
public:
        void foo(int i);

};

class Child : public Parent {
public:
        void foo(int i, int i);

};

The following code fragment does not work (it doesn't compile, g++
complains about 'no matching function call for Child::foo(int)':

...
Child c;
int k = 0;
c.foo(k);
...

I assumed that by inheriting the base class, the 'Child' class would
have two 'foo' methods, with different parameters. Apparently not. Adding

void foo(int i) { Parent::foo(i); }

to the Child class, fixes it, but is that how it should be done? Why is
the Parent's foo() not polymorphised-inherited by Child?

TIA,
Bart

Bart,

Couple of things to get out of the way first:
1) There is no polymorphism at all. Polymorphism is when you have
virtual functions.
2) Child::foo() is illegal as it has two parameters called "i".


What you're attempting is overloading. When Child introduces a method
called foo, it hides all the other methods from its base classes with
the same name. You can still call it like this:

int main()
{
Child c;
int k = 0;
c.Parent::foo(k); // <--- We want to call Parent's foo()
}

Another alternative is to unhide foo with Parent like this:


class Parent {
public:
void foo(int i)
{
}
};


class Child : public Parent {
public:
void foo(int i, int j)
{
}
using Parent::foo; // <--- Unhide foo() from Parent
};

int main()
{
Child c;
int k = 0;
c.foo(k);
}
 
N

newbarker

Hello,

I created the following inheritance:

class Parent {
public:
        void foo(int i);

};

class Child : public Parent {
public:
        void foo(int i, int i);

};

The following code fragment does not work (it doesn't compile, g++
complains about 'no matching function call for Child::foo(int)':

...
Child c;
int k = 0;
c.foo(k);
...

I assumed that by inheriting the base class, the 'Child' class would
have two 'foo' methods, with different parameters. Apparently not. Adding

void foo(int i) { Parent::foo(i); }

to the Child class, fixes it, but is that how it should be done? Why is
the Parent's foo() not polymorphised-inherited by Child?

TIA,
Bart

Bart,

Couple of things to get out of the way first:
1) There is no polymorphism at all. Polymorphism is when you have
virtual functions.
2) Child::foo() is illegal as it has two parameters called "i".


What you're attempting is overloading. When Child introduces a method
called foo, it hides all the other methods from its base classes with
the same name. You can still call it like this:

int main()
{
Child c;
int k = 0;
c.Parent::foo(k); // <--- We want to call Parent's foo()
}

Another alternative is to unhide foo with Parent like this:


class Parent {
public:
void foo(int i)
{
}
};


class Child : public Parent {
public:
void foo(int i, int j)
{
}
using Parent::foo; // <--- Unhide foo() from Parent
};

int main()
{
Child c;
int k = 0;
c.foo(k);
}
 
B

Bart Friederichs

Couple of things to get out of the way first:
1) There is no polymorphism at all. Polymorphism is when you have
virtual functions.

Ah. I thought polymorphism was having the same method name with
different parameters. Guess I mixed up some terminology.
2) Child::foo() is illegal as it has two parameters called "i".

That was a typo.
Another alternative is to unhide foo with Parent like this:


class Parent {
public:
void foo(int i)
{
}
};


class Child : public Parent {
public:
void foo(int i, int j)
{
}
using Parent::foo; // <--- Unhide foo() from Parent
};

I'd assume it is automatically unhidden, because it has a different
prototype.

I never saw that use of 'using'. Thanks.

Bart
 
B

Bart Friederichs

Couple of things to get out of the way first:
1) There is no polymorphism at all. Polymorphism is when you have
virtual functions.

Ah. I thought polymorphism was having the same method name with
different parameters. Guess I mixed up some terminology.
2) Child::foo() is illegal as it has two parameters called "i".

That was a typo.
Another alternative is to unhide foo with Parent like this:


class Parent {
public:
void foo(int i)
{
}
};


class Child : public Parent {
public:
void foo(int i, int j)
{
}
using Parent::foo; // <--- Unhide foo() from Parent
};

I'd assume it is automatically unhidden, because it has a different
prototype.

I never saw that use of 'using'. Thanks.

Bart
 
G

gw7rib

Ah. I thought polymorphism was having the same method name with
different parameters. Guess I mixed up some terminology.

The terminology can be confusing.

Having functions with the same name but different parameters is called
overloading.

Having a member function with the same name and same parameters as in
a base function, and getting the computer to call the right one
depending on what type of object you actually have, is called
polymorphism, or virtual functions, or overriding.
I'd assume it is automatically unhidden, because it has a different
prototype.
I never saw that use of 'using'. Thanks.

The reason it's in the FAQ is because lots of people assume that.
Don't be too hard on yourself.
 
A

Ali Karaali

The terminology can be confusing.

Having functions with the same name but different parameters is called
overloading.

This is not an overloading. You can only overload a function in a same
scope. But foo( int ) and foo (int, int) are in different scope.
int main()
{
Child c;
int k = 0;
c.foo(k);
}

If you call the foo function via Child obcejt the complier look up the
foo function in the Child class but there in no function foo (int,
int). So that was an error. Child::foo function is a viable function
but it is not a candidate function because of parameters.

Karaali
 
T

tony_in_da_uk

This is not an overloading. You can only overload a function in a same
scope. But foo( int ) and foo (int, int) are in different scope.

Bart's expectation was that they'd be visible in the same scope.

Anyway, exactly what polymorphism is is popularly disputed. Some
people use it to refer to virtual dispatch based run-time polymorphism
by default, and explicitly say "compile-time polymorphism" when
thinking of templates, and would argue themselves blue in the face
that C++ doesn't have any other polymorphic mechanisms. With so many
computing "experts" floating around, polymorphism has inevitably been
redefined to mean whatever somebody meant when they said it, but IMHO
the best criteria is that it allows the same piece of source code to
generate different code depending on the types to which the variable
involved resolve. For example...

a = x + y

....is valid code whether a, x and y are ints or doubles. This relies
on compile-time polymorphism provided by the compiler itself. A good
test for polymorphic language features is can they be used to write...

is_less_than(x, y)

....where x and y are not both locked in to one specific type. C++
mechanisms that allow this include:

- preprocessor macros
- overloading
- virtual dispatch
- templates

All these mechanisms are polymorphic.

Still, the test isn't perfect: you could write an is_less_than(x, y)
implementation using memcmp() and sizeof that produced results that
were meaningful only in the sense that they were consistent (at least
for types without structure padding), and therefore useful for sorting/
searching, but it wouldn't actually be polymorphic because there
hasn't been type-driven code generation. That's more in line with C-
style generic programming ala the bsearch() or qsort() functions
common on UNIX platforms.

Of course there have been many other uses of the term "polymorphism"
over the years, such as to describe self-mutating virus code, a usage
that has nothing to do with types at all....

Tony
 
P

Pranav

Bart's expectation was that they'd be visible in the same scope.

Anyway, exactly what polymorphism is is popularly disputed. Some
people use it to refer to virtual dispatch based run-time polymorphism
by default, and explicitly say "compile-time polymorphism" when
thinking of templates, and would argue themselves blue in the face
that C++ doesn't have any other polymorphic mechanisms. With so many
computing "experts" floating around, polymorphism has inevitably been
redefined to mean whatever somebody meant when they said it, but IMHO
the best criteria is that it allows the same piece of source code to
generate different code depending on the types to which the variable
involved resolve. For example...

a = x + y

...is valid code whether a, x and y are ints or doubles. This relies
on compile-time polymorphism provided by the compiler itself. A good
test for polymorphic language features is can they be used to write...

is_less_than(x, y)

...where x and y are not both locked in to one specific type. C++
mechanisms that allow this include:

- preprocessor macros
- overloading
- virtual dispatch
- templates

All these mechanisms are polymorphic.

Still, the test isn't perfect: you could write an is_less_than(x, y)
implementation using memcmp() and sizeof that produced results that
were meaningful only in the sense that they were consistent (at least
for types without structure padding), and therefore useful for sorting/
searching, but it wouldn't actually be polymorphic because there
hasn't been type-driven code generation. That's more in line with C-
style generic programming ala the bsearch() or qsort() functions
common on UNIX platforms.

Of course there have been many other uses of the term "polymorphism"
over the years, such as to describe self-mutating virus code, a usage
that has nothing to do with types at all....

Tony

Preprocessor Macros are preprocessed before compilation, How can you
say that they are polymorphic in nature, Preprocessor directives are
resolved while preprocessing..!!
 
J

James Kanze

On Sep 9, 5:26 am, Ali Karaali <[email protected]> wrote:

[...]
Anyway, exactly what polymorphism is is popularly disputed.

The C++ has a definition, which is valid for C++.
Some people use it to refer to virtual dispatch based run-time
polymorphism by default,

That's the way the standard uses it, and without qualification,
I think it's what most people would understand.
and explicitly say "compile-time polymorphism" when thinking
of templates, and would argue themselves blue in the face that
C++ doesn't have any other polymorphic mechanisms.

The only other "definition" I've seen is simply that a function
call may resolve to different functions, depending on the types
involved. Whether the "resolution" is at compile time
(templates and function overload resolution), link time
(different implementations of the same function, in different
object files) or runtime.
With so many computing "experts" floating around, polymorphism
has inevitably been redefined to mean whatever somebody meant
when they said it, but IMHO the best criteria is that it
allows the same piece of source code to generate different
code depending on the types to which the variable involved
resolve.

Which would exclude virtual function resolution. I've never
heard or seen that definition.
For example...
a = x + y
...is valid code whether a, x and y are ints or doubles. This
relies on compile-time polymorphism provided by the compiler
itself. A good test for polymorphic language features is can
they be used to write...
is_less_than(x, y)
...where x and y are not both locked in to one specific type.
C++ mechanisms that allow this include:
- preprocessor macros
- overloading
- virtual dispatch
- templates

And by providing different implementations in different object
files, the user choosing at link time. (And what about
providing different implementations in dynamically linked object
files:)? Runtime polymorphism? Certainly not what most people
would understand by it.)
All these mechanisms are polymorphic.
Still, the test isn't perfect: you could write an
is_less_than(x, y) implementation using memcmp() and sizeof
that produced results that were meaningful only in the sense
that they were consistent (at least for types without
structure padding), and therefore useful for sorting/
searching, but it wouldn't actually be polymorphic because
there hasn't been type-driven code generation. That's more in
line with C- style generic programming ala the bsearch() or
qsort() functions common on UNIX platforms.

The point about polymorphism is that the implementation isn't
fixed by the function call itself.
 
T

tony_in_da_uk

Some people use ["polymorphism"] to refer to virtual dispatch
based run-time polymorphism by default,

That's the way the standard uses it, and without qualification,
I think it's what most people would understand.

I agree that true, and believe it's rather unfortunate, for the C++
community. Encouraging an appreciation of the similarities and
contrasts between polymorphic mechanisms tends to make for better
programmers.
The only other "definition" I've seen is simply that a function
call may resolve to different functions, depending on the types
involved.  Whether the "resolution" is at compile time
(templates and function overload resolution), link time
(different implementations of the same function, in different
object files) or runtime.

Yes, this expresses the essence I botched an attempt to capture below.
Which would exclude virtual function resolution.  I've never
heard or seen that definition.

Sorry. "generate" should say "generate or invoke" - got too caught up
thinking about the variations of compile-time polymorphism as I was
typing.
And by providing different implementations in different object
files, the user choosing at link time.  (And what about
providing different implementations in dynamically linked object
files:)?  Runtime polymorphism?  Certainly not what most people
would understand by it.)

These don't resemble the mechanisms I describe in that they not
automated. You may think the linker is automated, but not for
performing a polymorphic task. Switching between implementations for
the same type differs from generating or switching between code based
on data types. If the app side has precompiled code for a specific
type, and it's calling a library function, they'll typically be
matched on the type-encoded mangled name. Any polymorphism involved
may have happened earlier during the resolution to a mangled name.
Even for extern "C" functions, the linker doesn't choose based on
type... unless you imagine someone manually linking calls ala `extern
"C" fn(void*); fn(&X());' to an implementation customised for type X.
That would be perverse, and as you say, not what most people
understand as polymorphism.
The point about polymorphism is that the implementation isn't
fixed by the function call itself.

A function pointer allows that, but is in no way polymorphic. It's
the ability to vary the types and get custom behaviour that defines
polymorphism.

Tony
 
T

tony_in_da_uk

Preprocessor Macros are preprocessed before compilation, How can you
say that they are polymorphic in nature, Preprocessor directives are
resolved while preprocessing..!!

I'll argue from the assumption that you accept templates as
polymorphic - let me know if not. How does instantiating a template
differs from a macro? In some cases, out-of-line implementation
reduces bloat, template have better and earlier error messages, and
they do fit in to the C++ type system properly, but for many purposes
they achieve identical - polymorphic - behaviour/results. They
"instantiate" the specified algorithmic code using arguments of
differing types. Of course, with macros you're only actually
leveraging the compiler's normal low-level polymorphic features,
whereas should a template instantiation happen to be out-of-line then
templates can require additional polymorphic dispatch from the
compiler to get the right instantiation called, but that doesn't even
affect client usage.

Tony
 
T

tony_in_da_uk

How is the following not polymorphic?

struct Base {
void (*foo)(Base*);
};

struct Derived : Base {
};

void impa(Base* b) {
cout << "impa\n";
}

void impb(Base* b) {
cout << "impb\n";
}

void bar(Base* b) {
b->foo(b);
}

int main() {
Base b;
b.foo = &impa;
Derived d;
d.foo = &impb;

bar( &b );
bar( &d );
}

The above could be considered more polymorphic than C++s virtual table
system. After all, I can vary what function is called at runtime on a
per object basis.

In the code above you explicitly point two object's function pointers
at different implementations. Then you call them. There's nothing
switched on type, except in your head where you must believe that it
was due to the types that you picked those functions. I declare your
head polymorphic, but not your code. Nothing polymorphic has been
done for you. That Derived is derived is an irrelevance, except in as
much as you're illustrating the opposite of polymorphism: the ability
of one instantiation/compilation (of bar) to ignore the differences
between several types. That's more related to the old void* qsort
stuff mentioned earlier.
To me, polymorphism is simply having the computer take care of your
'if's and 'switch'es implicitly. I can see making the case that taking
care of #if implicitly can be considered (compile time) polymorphism.

It's an interesting postulation, but I think there's a legitimate
distinction to be made....

Tony
 
J

James Kanze

On Sep 9, 4:56 pm, James Kanze <[email protected]> wrote:

[...]
These don't resemble the mechanisms I describe in that they
not automated. You may think the linker is automated, but not
for performing a polymorphic task. Switching between
implementations for the same type differs from generating or
switching between code based on data types.

How is this really any different from invoking a virtual
function through a pointer to base? The actual type referred to
in the source code is the same; the function called has a
different implementation. In many ways, this is closer to
traditional polymorphism than are templates. Traditional
polymorphism is common interface, different implementation,
where as templates are different interface, common
implementation.
If the app side has precompiled code for a specific type, and
it's calling a library function, they'll typically be matched
on the type-encoded mangled name. Any polymorphism involved
may have happened earlier during the resolution to a mangled
name. Even for extern "C" functions, the linker doesn't
choose based on type... unless you imagine someone manually
linking calls ala `extern "C" fn(void*); fn(&X());' to an
implementation customised for type X. That would be perverse,
and as you say, not what most people understand as
polymorphism.

What most people understand by polymorphism, most of the time,
is that calls through a type base resolve to different
implementations.
A function pointer allows that, but is in no way polymorphic.

Sure it is. At the lowest level, it's the only mechanism
available for runtime polymorphism, and when you implement a
polymorphic system in C, it's what you use. (It's also what the
compiler uses to implement polymorphism in C++.)
It's the ability to vary the types and get custom behaviour
that defines polymorphism.

It's the ability to get different behavior from the same
source code function call which defined polymorphism.
 
T

tony_in_da_uk

How is this really any different from invoking a virtual
function through a pointer to base?  The actual type referred to
in the source code is the same; the function called has a
different implementation.  In many ways, this is closer to
traditional polymorphism than are templates.  Traditional
polymorphism is common interface, different implementation,
where as templates are different interface, common
implementation.

Sorry - got a flight to catch soon - not much time. Discussed below
re function pointer initialisation.
It's the ability to get different behavior from the same
source code function call which defined polymorphism.

Consider:

int n = fn();
printf("%d", n);

Clearly nothing polymorphic. But if n is 1 versus -10 different code
paths will be taken, loops will loop different numbers of time, and
different behaviour obtained. Still not polymorphic. Why? Because
the code executed is not a function of the type of data being used -
it's the fact that the switching is done on type that's the essence of
polymorphism.
Sure it is. At the lowest level, it's the only mechanism
available for runtime polymorphism, and when you implement a
polymorphic system in C, it's what you use. (It's also what the
compiler uses to implement polymorphism in C++.)

The function pointer itself is not polymorphic. In compiler-generated
virtual dispatch, it's the automated initialisation of the pointer
that's the polymorphic bit.

Tony
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top