polymorphism; dummy parameters

V

vsgdp

Say you have 3 child classes A, B, C deriving from a parent class P
with pure virtual function f.

Suppose A::f(x1); // A::f depends only on x1
Suppose B::f(x1, x2); // B::f depends on x1 and x2
Suppose C::f(x1, x2, x3); // C::f depends on x1, x2, x3

Is it bad form to define P::f(x1, x2, x3), and then A::f and B::f just
ignore the parameters it does not need?

In some sense this could be justified; you could say that for A::f, x2
and x3 are just "zero" or some identity value that doesn't actually
affect the output.

Any thoughts on this?

I think it is okay occasionally if not abused often, but I would like
the opinion of the C++ programming community.

For those that want some context, basically I have a Light class and I
derive:

DirectionalLight, PointLight, SpotLight, AreaLight. The area light
implementation requires some special data the others do not; this data
also varies over time so I can't just set it at construction time. I
can't set the area light's specific data at runtime either without
knowing its specific type (defeats polymorphism). So I am thinking
the best solution would be to just pass the data to the pure virtual
function, even though only area lights will use the data.
 
V

Victor Bazarov

vsgdp said:
Say you have 3 child classes A, B, C deriving from a parent class P
with pure virtual function f.

Suppose A::f(x1); // A::f depends only on x1
Suppose B::f(x1, x2); // B::f depends on x1 and x2
Suppose C::f(x1, x2, x3); // C::f depends on x1, x2, x3

Is it bad form to define P::f(x1, x2, x3), and then A::f and B::f just
ignore the parameters it does not need?

Yes. But you'll be better off asking about it in 'comp.object'.
Here, in the multi-paradigm, "do as I please as long as it's legal",
land, it's perfectly OK, if it works for you.
In some sense this could be justified; you could say that for A::f, x2
and x3 are just "zero" or some identity value that doesn't actually
affect the output.

Any thoughts on this?

Not many, no. Depends on the problem you're solving, I guess.
I think it is okay occasionally if not abused often, but I would like
the opinion of the C++ programming community.

For those that want some context, basically I have a Light class and I
derive:

DirectionalLight, PointLight, SpotLight, AreaLight. The area light
implementation requires some special data the others do not; this data
also varies over time so I can't just set it at construction time.

So, it seems that you need a specific "set my stuff" function, which
should probably be very generic and implement some kind of "property"
thing.
I
can't set the area light's specific data at runtime either without
knowing its specific type (defeats polymorphism). So I am thinking
the best solution would be to just pass the data to the pure virtual
function, even though only area lights will use the data.

Take a look at "properties". If you give your properties names, by
which you will be able to differenciate them, you will be able to set
them independently. You can have a single 'set(string, void*)' function
or add another 'set_many(vector<string>,vector<void*>)'.

I am not sure it's better than stuffing the base class with the arguments
it's not going to use (that's true for any pure virtual function, no?);
at least it's a bit more generic (and you can probably find some more
or less generalized implementations out there in the open).

V
 
?

=?iso-8859-1?q?Kirit_S=E6lensminde?=

DirectionalLight, PointLight, SpotLight, AreaLight. The area light
implementation requires some special data the others do not; this data
also varies over time so I can't just set it at construction time. I
can't set the area light's specific data at runtime either without
knowing its specific type (defeats polymorphism). So I am thinking
the best solution would be to just pass the data to the pure virtual
function, even though only area lights will use the data.

These things are much easier with a concrete example :)

A normal OO approach would be to move the management of the changes
into a separate hierarchy (I guess that you're changing the parameters
during the course of animating the model).

You can now pass the manager (think of it like a puppet master where
the light is the puppet it is controlling) into the method, but in C++
you're going to need a downcast which feels icky.

A better way is to have all interaction occur within the puppet master
objects which then set the model elements for each frame. Now instead
of creating a model element on its own you always create a pair of
model element and its puppet master. The user interacts with the
puppet master, but the model elements can still be hived off for
rendering of individual frames (and the rendering code will be the
same, only the animation control will change).


K
 
J

Jim Langston

vsgdp said:
Say you have 3 child classes A, B, C deriving from a parent class P
with pure virtual function f.

Suppose A::f(x1); // A::f depends only on x1
Suppose B::f(x1, x2); // B::f depends on x1 and x2
Suppose C::f(x1, x2, x3); // C::f depends on x1, x2, x3

Is it bad form to define P::f(x1, x2, x3), and then A::f and B::f just
ignore the parameters it does not need?

In some sense this could be justified; you could say that for A::f, x2
and x3 are just "zero" or some identity value that doesn't actually
affect the output.

Any thoughts on this?

I think it is okay occasionally if not abused often, but I would like
the opinion of the C++ programming community.

For those that want some context, basically I have a Light class and I
derive:

DirectionalLight, PointLight, SpotLight, AreaLight. The area light
implementation requires some special data the others do not; this data
also varies over time so I can't just set it at construction time. I
can't set the area light's specific data at runtime either without
knowing its specific type (defeats polymorphism). So I am thinking
the best solution would be to just pass the data to the pure virtual
function, even though only area lights will use the data.

It sounds to me like P:f(x1, x2, x3) should actually be in the constructor,
no? Okay, you don't now it's type, but if you could set it in the
constructor, that would be the way to go, right? So, do it in the
constructor. Have each derived classes' constructor initialize as required.

Let me try to give an example. The following compiles.

#include <iostream>
#include <string>

struct Vector3D
{
double x;
double y;
double z;
};

class Light
{
public:
Light( unsigned long Color, Vector3D Pos ): Color_( Color ), Pos_( Pos )
{}
virtual ~Light() {}
virtual void Render() { std::cout << "Rendering from Light\n"; }
protected:
unsigned long Color_;
Vector3D Pos_;
};

class DirectionalLight: public Light
{
public:
DirectionalLight( unsigned long Color, Vector3D Pos, Vector3D Aim ):
Light( Color, Pos ), Direction_( Aim ) {}
void Render() { std::cout << "Rendering from DirectionLight\n"; }
private:
Vector3D Direction_;
};

class PointLight: public Light
{
public:
PointLight( unsigned long Color, Vector3D Pos, double Radius ): Light(
Color, Pos ), Radius_( Radius ) {}
private:
double Radius_;
};

class SpotLight: public Light
{
public:
SpotLight( unsigned long Color, Vector3D Pos, Vector3D Aim, double
Radius ): Light( Color, Pos ), Direction_( Aim ), Radius_( Radius ) {}
private:
Vector3D Direction_;
double Radius_;
};

class AreaLight: public Light
{
public:
AreaLight( unsigned long Color, Vector3D Pos, double Radius ): Light(
Color, Pos ), Radius_( Radius ) {}
private:
double Radius_;
};

int main()
{
Vector3D Center = { 10.0, 20.0, 30.0 };
Vector3D Aim = { 5.0, 5.0, 5.0 };
unsigned int Color = 0xFF00FFFF;
Light* Light1 = new Light( Color, Center );
Light* Light2 = new DirectionalLight( Color, Center, Aim );
Light* Light3 = new PointLight( Color, Center, 20.5 );
Light* Light4 = new SpotLight( Color, Center, Aim, 10.2 );
Light* Light5 = new AreaLight( Color, Center, 5.5 );

delete Light1;
delete Light2;
delete Light3;
delete Light4;
delete Light5;
}

Now, if your'e going to need more information in Light (Radius seems to be
largly common, I would probably move it there and initialize it to 0.0 for
lights that don't need it).

This should be enough for you to get started on. If you have any questions
let us know.
 

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,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top