Sign in to follow this  

Overloading an inherited function

This topic is 3783 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I would think it is possible to overload an base function in an inherited class like so:
class Base
{
public:
   void setValue(int v) { value = v; }
protected:
   int value;
};

class Derived: public Base
{
public:
   void setValue(int v, int i) { value = v; item = i; }
private:
   int item;
};

main()
{
   Derived d;
   d.setValue(10); // this should call the Base::setValue function right?
}

But when I try to compile this (VS2005) I get an error saying: "Derived::setValue' : function does not take 1 arguments" So am I just not understanding C++ right or what? Or is there some way that I can overload a base function in an inherited class?

Share this post


Link to post
Share on other sites
The complicated answer starts with "Name resolution occurs before overload resolution" and goes on from there. The simple answer is "put using Base::setValue; in the definition of Derived".

Share this post


Link to post
Share on other sites
This is also somewhat fishy.

Your value has no business being protected. You have a setter, provide a getter as well.

In derived class call the base class' setValue, and only access item locally.

But even more, there's little reason to use inheritance here:

template < typename T >
class Base
{
public:
void setValue( T &v )
{
value = v;
}

const T &getValue( ) const {
return value;
}

T &getValue( ) {
return value;
}
private:
T value;
};

typedef Base<int> IntValue;
typedef Base< std::pair< int, int> > IntPairValue;

IntPairValue x;
x.setValue( std::make_pair( 11, 22 ) );
std::cout << x.getValue().first << std::endl;
std::cout << x.getValue().second << std::endl;



If you then still feel the need to provide syntactic sugar, derive templated classes:

class Derived : public Base< IntPairValue >
{
public:
int getItem() const {
return getValue().second;
}
};



At least you separate your concerns. Storage is defined by one class, additional functions, which really don't care about storage in inherited classes.

Share this post


Link to post
Share on other sites
Thanks Sneftel, that's what I was looking for. I guess its just the order and way the code is compiled that I didn't understand, your fix is what I was seeking though. Antheus, thanks for an interesting example, I know my example code didn't really make sense, it was merely to show my problem as simply as possible.

Share this post


Link to post
Share on other sites
Let's try giving the complicated explanation. Name resolution occurs before overload resolution. What that means is when the compiler sees a given identifier it goes through a process to figure out what that identifier refers to. This is called name resolution.

Let's say the compiler sees "fred" in a member function definition. First the compiler looks in the local scope. If it finds a declaration in the local scope for that identifier, it says "Ok, the fred I just found refers to this thing in local scope." If it doesn't find anything in local scope, it goes one scope out in the current function. Then, a scope further out until it runs out of scopes in the the function. Once it exhausts the function scopes, it looks in the scope of the class the member function is defined in. If it doesn't find anything there it takes a look in the scopes of any base classes. If it doesn't find anything there it looks in the namespace scopes. Take this code for example:

int fred(void);

struct Base {
int fred;
};

struct Example : public Base {
float fred;

void member_function(double fred) {
for (short fred = 0; fred < 10; ++fred) {
fred = 0;
}
}
};

There are a lot of freds in this code. At the point of the assignment statement "fred = 0" which fred does the compiler think it refers to? In this case it'd be the short fred in the for loop. If we called the loop variable "barney" instead, fred would refer to the double fred that's the function argument. If we called the function argument "wilma", then it would think that fred would refer to the fred member variable inside Example. Call that "dino" instead and fred would refer to the int fred in Base. Call that fred "betty" and fred would refer to the fred() function in the namespace scope.

So let's go back to your code. Let's do the name resolution for the "setValue" in "d.setValue(10);" Well, we can skip all the local function stuff because the dot tells us that the name is somewhere in d's class' scope. d is a Derived, so first the compiler searches for "setValue" in Derived, and it finds it. So it thinks setValue is a void (Derived::)(int v, int i), so when you call it with 10, it says "wrong number of arguments".

So what happens when you put in the using statement? That basically tells the compiler, "Yeah, I know you've found a setValue here, but if you're looking for setValue, could you go look for the setValue in Base too?" So the compiler then finds both setValue declarations. Now when you have "d.setValue(10)", the compiler can think to itself, "Hey I've got two setValue functions here, got to try them both out." That's the part called overload resolution.

Share this post


Link to post
Share on other sites

This topic is 3783 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this