![]() |
| |||||||
![]() |
| | LinkBack | Thread Tools | Display Modes |
| | #1 |
| Registered User Join Date: May 2009
Posts: 8
| rvirtual and inline function with different prototypes (to enforce default parameter) Code: class B
{
public:
virtual void Foo( int x, int mode );
};
class C : public B
{
public:
virtual void Foo( int x, int mode );
};
Code: C* bla; bla->Foo(1,0); Now, I want to have a default value for the 'mode' parameter. But if I do this: Code: class B
{
public:
virtual void Foo( int x, int mode=0 );
};
Code: bla->Foo(1); Ok, so I thought I could work around this by adding an inline wrapper function to the base class, which calls the actual function, like this: Code: class B
{
public:
virtual void Foo( int x, int mode );
inline void Foo( int x ) { Foo(x,0); }
};
Why is this? Is it somehow invalid or ambiguous what I'm doing here? (PS. Workarounds: add the =0 default in all derived classes as well (lotsa work), or keep the above inline function and change the function calls into bla->B::Foo(1) or ((B*)bla)->Foo(1) (somewhat less work in my case), but I'm just wondering) |
| Jace is offline | |
| | #2 |
| Senior software engineer Join Date: Mar 2007 Location: Portland, OR
Posts: 5,379
| In your base class B: Code: class B
{
public:
virtual void Foo( int x, int mode );
virtual void Foo( int x ) { Foo( x, 0 ); }
};
EDIT: Hmm, I see you've tried that. I don't know why it shouldn't work. EDIT EDIT: It works if you declare Foo( int ) as virtual. I think it's starting to make sense now. The overload set has to be all virtual or all non-virtual, I think. But that was something I was not aware of.
__________________ "Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot Last edited by brewbuck; 06-17-2009 at 05:44 PM. |
| brewbuck is online now | |
| | #3 | |
| Registered User Join Date: Sep 2004 Location: California
Posts: 2,845
| Quote:
| |
| bithub is offline | |
| | #4 |
| Registered User Join Date: May 2009
Posts: 8
| Thanks, but unfortunately it doesn't work here. What kind of compiler are you using? Visual Studio 8 here. |
| Jace is offline | |
| | #5 |
| Registered User Join Date: Jan 2008
Posts: 575
| O_o To much hassle... just dropping some notes and code. If you are not overriding the behavior allow the declaration of the inherited function to be inherited. (Do not declare the function again in a derived class unless you need to do so for other reasons.) Code: class B
{
public:
virtual void Foo( int x, int mode = 7)
{
}
};
class C : public B
{
public:
//virtual void Foo( int x, int mode );
};
int main()
{
C a;
a.Foo(0);
return(0);
}
Code: class B
{
public:
virtual void Foo( int x, int mode = 7)
{
}
};
class C : public B
{
public:
virtual void Foo( int x, int mode = 7)
{
}
};
int main()
{
C a;
a.Foo(0);
return(0);
}
I hate this method because the default value can get out of sync. (If the default value is out of sync you violate "is-a" and the more appropriate "constrained-as".) You can go a more robust route by changing them both at the same time by using a separate value to store the default value. Code: class B
{
public:
virtual void Foo( int x, int mode = default_mode)
{
}
static const int default_mode = 7;
};
class C : public B
{
public:
virtual void Foo( int x, int mode = default_mode)
{
}
};
int main()
{
C a;
a.Foo(0);
return(0);
}
As with the other path, you should not use a declaration in the derived class unless you need to override the behavior. Code: class B
{
public:
virtual void Foo( int x)
{
this->Foo(x, 7);
}
virtual void Foo( int x, int mode)
{
}
};
class C : public B
{
public:
//virtual void Foo( int x, int mode);
};
int main()
{
C a;
a.Foo(0);
return(0);
}
You should be careful with this path because it is easy to fall into the trap of only declaring the inherited short interface function. (I've included it for the sake of completeness. It is the following example.) This approach will fail to compile for various reasons. Code: class B
{
public:
virtual void Foo( int x)
{
this->Foo(x, 7);
}
virtual void Foo( int x, int mode)
{
}
};
class C : public B
{
public:
virtual void Foo(int x);
virtual void Foo( int x, int mode)
{
}
};
int main()
{
C a;
a.Foo(0);
return(0);
}
Code: class B
{
public:
virtual void Foo( int x)
{
this->Foo(x, 7);
}
virtual void Foo( int x, int mode)
{
}
};
class C : public B
{
public:
virtual void Foo(int x)
{
this->Foo(x, 7);
}
virtual void Foo( int x, int mode)
{
}
};
int main()
{
C a;
a.Foo(0);
return(0);
}
In most cases you will only tell the compiler to use the functions from the derived class with a using declaration. Code: class B
{
public:
virtual void Foo( int x)
{
this->Foo(x, 7);
}
virtual void Foo( int x, int mode)
{
}
};
class C : public B
{
public:
using B::Foo;
virtual void Foo( int x, int mode)
{
}
};
int main()
{
C a;
a.Foo(0);
return(0);
}
Soma |
| phantomotap is offline | |
| | #6 |
| Registered User Join Date: May 2009
Posts: 8
| Thanks for your suggestions. Of course I'm only re-declaring the function in a derived class if I actually need to override its implementation there. The problem is I have over hundred classes like C which derive from B and have to override that function. But I think I'll stick to the method of defining the default value in the baseclass, and reuse the same default wherever I override it. Except for a one time effort (probably a smart regexp search & replace can do the trick), this seems to offer the least hassle and the best maintainability. Except to tackle the header-only distribution issue, I'll use an ENUM instead: Code: class B
{
public:
enum { default_mode = 17; }
virtual void Foo( int x, int mode = default_mode );
};
class C : public B
{
public:
virtual void Foo( int x, int mode = default_mode );
};
C *a;
a->Foo(0);
|
| Jace is offline | |
| | #7 | |
| The larch Join Date: May 2006
Posts: 3,082
| Code: class B
{
public:
enum { default_mode = 17 };
virtual void Foo( int x, int mode ) {}
void Foo(int x) { Foo(x, default_mode); }
};
class C : public B
{
public:
virtual void Foo( int x, int mode ) {}
};
int main()
{
B *a = new C;
a->Foo(0);
}
__________________ I might be wrong. Quote:
| |
| anon is offline | |
| | #8 |
| Registered User Join Date: May 2009
Posts: 8
| |
| Jace is offline | |
| | #9 | ||
| Registered User Join Date: Jun 2005
Posts: 1,343
| Quote:
Code: int main()
{
C *c = new C;
c->Foo(0);
}
Quote:
One common way to avoid unwanted consequences of the hiding rule in this case is to use a function of a different name. Accordingly, I would do this; Code: class B
{
public:
void Foo( int x, int mode = 7); // assuming default value of mode is 7
protected:
virtual void FooImplementation(int x, int mode);
};
void B::Foo(int x, int mode)
{
FooImplementation(x, mode); // this is a polymorphic call
}
class C : public B
{
protected:
virtual void FooImplementation( int x, int mode );
};
__________________ Right 98% of the time, and don't care about the other 3%. | ||
| grumpy is offline | |
| | #10 | |
| Registered User Join Date: May 2009
Posts: 8
| Quote:
Thanks! | |
| Jace is offline | |
![]() |
| Tags |
| default parameter, function, inline, virtual |
| Thread Tools | |
| Display Modes | |
|