Accessing virtuals in base class

J

Jo

Hi,

Is there a generic way to access the (virtual) functions in the base
class of a class?

Like in:

if (!this->Foo(something)) return(((Base*)this)->Foo(something)); // for
a normal member function
if (!this->Foo(something)) return(this->Base::Foo(something)); // for
a virtual member function

I would like to do this in a generic way, thus without having to put
this line in every class specifying the proper base class

Cheers,

Jo
 
J

Juha Nieminen

Jo said:
I would like to do this in a generic way, thus without having to put
this line in every class specifying the proper base class

How could the compiler know *which* version of the function you
want to call if you don't specify it?

Just call: Base::Foo(something);
 
J

Jo

Juha said:
Jo wrote:



How could the compiler know *which* version of the function you
want to call if you don't specify it?

Just call: Base::Foo(something);

I mean the immediate base class "one up" in the inheritance tree.

That should be no problem for the compiler.
 
Z

Zeppe

Jo said:
I mean the immediate base class "one up" in the inheritance tree.

That should be no problem for the compiler.

no? what about this:

class A
{
public:
virtual ~A() {}
virtual void foo() { std::cout << "A::foo\n"; }
};

class B
{
public:
virtual ~B() {}
virtual void foo() { std::cout << "B::foo\n"; }
};

class C
: public A, public B
{
public:
virtual ~C() {}
virtual void foo() { std::cout << "C::foo\n"; }
};

what function should call C, given that inherits from two different
classes that define the same virtual function? On the other side, I
don't see what kind of problem do you have in specifying the base class,
when it's needed.

Regards,

Zeppe
 
J

Jo

Zeppe said:
no? what about this:

class A
{
public:
virtual ~A() {}
virtual void foo() { std::cout << "A::foo\n"; }
};

class B
{
public:
virtual ~B() {}
virtual void foo() { std::cout << "B::foo\n"; }
};

class C
: public A, public B
{
public:
virtual ~C() {}
virtual void foo() { std::cout << "C::foo\n"; }
};

what function should call C, given that inherits from two different
classes that define the same virtual function? On the other side, I
don't see what kind of problem do you have in specifying the base
class, when it's needed.

Agreed, in this case the compiler could warn that there is ambiguity of
course. Just like the compiler does warn about ambiguity in some other
cases.

But in many cases the corresponding direct base class function should be
very definable.

But reading your answers i suppose there is no such syntax to do so..?

(though i thought to remember that i saw that somewhere)
 
J

Jerry Coffin

[ ... ]
I mean the immediate base class "one up" in the inheritance tree.

That should be no problem for the compiler.

....except when it is, such as when you've used multiple inheritance:

struct B1 {
virtual int foo();
};
struct B2 {
virtual inf foo();
};

struct D : B1, B2 {
void bar() {
// if we invoke foo() here, should it mean B1::foo()
// or B2::foo()?
}
};

I'm less concerned over the mechanism than your design -- why do you
want to do this in the first place? If you're doing it so often that you
need/want a way to do it conveniently/generically, that sounds to me
like you're fairly routinely creating derived classes that aren't really
substitutable for the base and overriding virtual functions in a way
that they aren't really polymorphic.
 
Z

Zeppe

Jo said:
> Agreed, in this case the compiler could warn that there is ambiguity
of course. Just like the compiler does warn about ambiguity in some
other cases.
>
> But in many cases the corresponding direct base class function should
be very definable.

it's the concept itself that is ambiguous... why for example the
previous class in the hierarchy and not the first one? And I still don't
understand why you may need this kind of syntax...
> But reading your answers i suppose there is no such syntax to do so..?

no, there isn't AFAIK. It would have been a specific extension for a
specific situation that is not even a problem given that there is no
situation in which you don't have a valid alternative.
> (though i thought to remember that i saw that somewhere)
>

I don't think so, maybe I'm wrong...

Regards,

Zeppe
 
B

Bo Persson

Jo wrote:
:: Zeppe wrote:
::
::: Jo wrote:
:::
:::: Juha Nieminen wrote:
::::
::::: Jo wrote:
:::::
:::::
:::::: I would like to do this in a generic way, thus without having
:::::: to put this line in every class specifying the proper base
:::::: class
::::::
:::::
:::::
::::: How could the compiler know *which* version of the function
::::: you want to call if you don't specify it?
:::::
::::: Just call: Base::Foo(something);
::::
::::
:::: I mean the immediate base class "one up" in the inheritance tree.
::::
:::: That should be no problem for the compiler.
:::
:::
::: no? what about this:
:::
::: class A
::: {
::: public:
::: virtual ~A() {}
::: virtual void foo() { std::cout << "A::foo\n"; }
::: };
:::
::: class B
::: {
::: public:
::: virtual ~B() {}
::: virtual void foo() { std::cout << "B::foo\n"; }
::: };
:::
::: class C
::: : public A, public B
::: {
::: public:
::: virtual ~C() {}
::: virtual void foo() { std::cout << "C::foo\n"; }
::: };
:::
::: what function should call C, given that inherits from two
::: different classes that define the same virtual function? On the
::: other side, I don't see what kind of problem do you have in
::: specifying the base class, when it's needed.
:::
::
:: Agreed, in this case the compiler could warn that there is
:: ambiguity of course. Just like the compiler does warn about
:: ambiguity in some other cases.
::
:: But in many cases the corresponding direct base class function
:: should be very definable.

If you need to refer to the direct base class, you can add a typedef
to you class.

class C : public A, public B
{
typedef A direct_base_class; // select the one you want

public:
virtual void foo()
{
direct_base_class::foo();

// do someting more

}

};

::
:: But reading your answers i suppose there is no such syntax to do
:: so..?

No, but you can easily use existing features when needed.


Bo Persson
 
J

Jo

Zeppe said:
of course. Just like the compiler does warn about ambiguity in some
other cases.
should be very definable.

it's the concept itself that is ambiguous... why for example the
previous class in the hierarchy and not the first one? And I still
don't understand why you may need this kind of syntax...


no, there isn't AFAIK. It would have been a specific extension for a
specific situation that is not even a problem given that there is no
situation in which you don't have a valid alternative.


I don't think so, maybe I'm wrong...


OK, what i want to do is having a kind of run time type information in a
basic way:

(see the BASE word, that's what i need)

class Object { // the very base class

virtual long GetObjectType() { return(' obj'); }
bool Is(long object_type) {
return(object_type==GetObjectType()); }
virtual bool IsInSomeWay(long object_type) {
return(object_type==GetObjectType()); }
};

class Figure : public Object {

virtual long GetObjectType() { return('figr'); }
virtual bool IsInSomeWay(long object_type) { if
(GetObjectType()==object_type) return(true); else
return(BASE::IsInSomeWay(object_type)); }
};

class Rectangle : public Figure {

virtual long GetObjectType() { return('rect'); }
};

class Circle : public Figure {

virtual long GetObjectType() { return('circ'); }
};

class Ellipse : public Figure {

virtual long GetObjectType() { return('ellp'); }
};

Ellipse *e = new Ellipse;
Circle *c = e;
c->IsInSomeWay('ellp'); // returns true
c->IsInSomeWay('circ'); // returns true
c->IsInSomeWay('rect'); // returns false

So this way the exact actual object type can be recalled, but also
wether it's actually derived from another type!
 
J

Jo

Jo said:
OK, what i want to do is having a kind of run time type information in
a basic way:

(see the BASE word, that's what i need)

class Object { // the very base class

virtual long GetObjectType() { return(' obj'); }
bool Is(long object_type) {
return(object_type==GetObjectType()); }
virtual bool IsInSomeWay(long object_type) {
return(object_type==GetObjectType()); }
};

class Figure : public Object {

virtual long GetObjectType() { return('figr'); }
virtual bool IsInSomeWay(long object_type) { if
(GetObjectType()==object_type) return(true); else
return(BASE::IsInSomeWay(object_type)); }
};

class Rectangle : public Figure {

virtual long GetObjectType() { return('rect'); }
};

class Circle : public Figure {

virtual long GetObjectType() { return('circ'); }
};

class Ellipse : public Figure {


This must be : "class Ellipse : public Circle" of course, sorry for the typo
virtual long GetObjectType() { return('ellp'); }
};

Ellipse *e = new Ellipse;
Circle *c = e;
c->IsInSomeWay('ellp'); // returns true
c->IsInSomeWay('circ'); // returns true
c->IsInSomeWay('rect'); // returns false

So this way the exact actual object type can be recalled, but also
wether it's actually derived from another type!



Or am i on a totally wrong path here?

Maybe i should use RTTI? But isn't that taking a lot of speed/memory
resources?

It's about a realtime code working on interupt level, so it must be
steady and fast code! (e.g. no mem allocs)
 
Z

Zeppe

Jo said:
Jo said:
OK, what i want to do is having a kind of run time type information in
a basic way:

[CUT]

So this way the exact actual object type can be recalled, but also
wether it's actually derived from another type!

Or am i on a totally wrong path here?

Maybe i should use RTTI? But isn't that taking a lot of speed/memory
resources?

It's about a realtime code working on interupt level, so it must be
steady and fast code! (e.g. no mem allocs)

It's a interesting problem, it makes sense (at compile time you should
be able to construct such a function that returns true for a set of
values, based on the inheritance of each class) and it shouldn't require
memory allocation. I think the solution is based on template, I've tried
to sketch a solution that uses an intermediate template class that has
as arguments the Actual class (CRTP) and the parent.

#include <string>
#include <iostream>

class Figure
{
public:
virtual ~Figure() {}
virtual std::string GetName() const = 0;
virtual bool IsType(const std::string name) const { return name ==
"Figure"; }
};

template <class Parent, class Actual>
class FigureT
: public Parent
{
public:
virtual std::string GetName() const { return "Figure"; }
virtual bool IsType(const std::string name) const { return name ==
static_cast<const Actual*>(this)->Actual::GetName() ||
Parent::IsType(name); }
};


class Square
: public FigureT<Figure,Square>
{
public:
virtual std::string GetName() const { return "Square"; }
};

class Ellipse
: public FigureT<Figure,Ellipse>
{
public:
virtual std::string GetName() const { return "Ellipse"; }
};

class Circle
: public FigureT<Ellipse,Circle>
{
public:
virtual std::string GetName() const { return "Circle"; }
};


int main()
{
Square sq;
std::string type;
char* yes = "yes";
char* no = "no";
type = "Square";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes : no)
<< "\n";
type = "Figure";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes : no)
<< "\n";
type = "Ellipse";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes : no)
<< "\n";

Ellipse el;

type = "Ellipse";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes : no)
<< "\n";
type = "Figure";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes : no)
<< "\n";
type = "Circle";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes : no)
<< "\n";

Circle ci;

type = "Figure";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes : no)
<< "\n";
type = "Ellipse";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes : no)
<< "\n";
type = "Circle";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes : no)
<< "\n";

}


I think you can start from here and improve this solution that is
somewhat messy. The concept is to implement some sort of recursion on
the function calls based on the templates arguments. With multiple
inheritance it won't work due to ambiguities... maybe it can be improved.

Regards,

Zeppe
 
J

Jo

Zeppe said:
Jo said:
Jo said:
OK, what i want to do is having a kind of run time type information
in a basic way:

[CUT]

So this way the exact actual object type can be recalled, but also
wether it's actually derived from another type!


Or am i on a totally wrong path here?

Maybe i should use RTTI? But isn't that taking a lot of speed/memory
resources?

It's about a realtime code working on interupt level, so it must be
steady and fast code! (e.g. no mem allocs)

It's a interesting problem, it makes sense (at compile time you should
be able to construct such a function that returns true for a set of
values, based on the inheritance of each class) and it shouldn't
require memory allocation. I think the solution is based on template,
I've tried to sketch a solution that uses an intermediate template
class that has as arguments the Actual class (CRTP) and the parent.

#include <string>
#include <iostream>

class Figure
{
public:
virtual ~Figure() {}
virtual std::string GetName() const = 0;
virtual bool IsType(const std::string name) const { return name ==
"Figure"; }
};

template <class Parent, class Actual>
class FigureT
: public Parent
{
public:
virtual std::string GetName() const { return "Figure"; }
virtual bool IsType(const std::string name) const { return name ==
static_cast<const Actual*>(this)->Actual::GetName() ||
Parent::IsType(name); }
};


class Square
: public FigureT<Figure,Square>
{
public:
virtual std::string GetName() const { return "Square"; }
};

class Ellipse
: public FigureT<Figure,Ellipse>
{
public:
virtual std::string GetName() const { return "Ellipse"; }
};

class Circle
: public FigureT<Ellipse,Circle>
{
public:
virtual std::string GetName() const { return "Circle"; }
};


int main()
{
Square sq;
std::string type;
char* yes = "yes";
char* no = "no";
type = "Square";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";
type = "Figure";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";
type = "Ellipse";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";

Ellipse el;

type = "Ellipse";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";
type = "Figure";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";
type = "Circle";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";

Circle ci;

type = "Figure";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";
type = "Ellipse";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";
type = "Circle";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";

}


I think you can start from here and improve this solution that is
somewhat messy. The concept is to implement some sort of recursion on
the function calls based on the templates arguments. With multiple
inheritance it won't work due to ambiguities... maybe it can be improved.

Thanks Zeppe.

You're thinking creatively :)

But to be honnest, the work that i should do to implement this with
templates is much more than the work i just wanted to spare out by
"automatically" refering to the direct base class.

So, for now, i think i'll stick with explicitly writing the
'BaseClass::' thing all the time...

And i'll think your idea over.

Cheers,

Jo
 
J

Jo

Jo said:
Zeppe said:
Jo said:
Jo wrote:

OK, what i want to do is having a kind of run time type information
in a basic way:

[CUT]

So this way the exact actual object type can be recalled, but also
wether it's actually derived from another type!



Or am i on a totally wrong path here?

Maybe i should use RTTI? But isn't that taking a lot of speed/memory
resources?

It's about a realtime code working on interupt level, so it must be
steady and fast code! (e.g. no mem allocs)

It's a interesting problem, it makes sense (at compile time you
should be able to construct such a function that returns true for a
set of values, based on the inheritance of each class) and it
shouldn't require memory allocation. I think the solution is based on
template, I've tried to sketch a solution that uses an intermediate
template class that has as arguments the Actual class (CRTP) and the
parent.

#include <string>
#include <iostream>

class Figure
{
public:
virtual ~Figure() {}
virtual std::string GetName() const = 0;
virtual bool IsType(const std::string name) const { return name
== "Figure"; }
};

template <class Parent, class Actual>
class FigureT
: public Parent
{
public:
virtual std::string GetName() const { return "Figure"; }
virtual bool IsType(const std::string name) const { return name
== static_cast<const Actual*>(this)->Actual::GetName() ||
Parent::IsType(name); }
};


class Square
: public FigureT<Figure,Square>
{
public:
virtual std::string GetName() const { return "Square"; }
};

class Ellipse
: public FigureT<Figure,Ellipse>
{
public:
virtual std::string GetName() const { return "Ellipse"; }
};

class Circle
: public FigureT<Ellipse,Circle>
{
public:
virtual std::string GetName() const { return "Circle"; }
};


int main()
{
Square sq;
std::string type;
char* yes = "yes";
char* no = "no";
type = "Square";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";
type = "Figure";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";
type = "Ellipse";
std::cout << "is sq a " << type << "? " << (sq.IsType(type) ? yes
: no) << "\n";
Ellipse el;

type = "Ellipse";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";
type = "Figure";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";
type = "Circle";
std::cout << "is el a " << type << "? " << (el.IsType(type) ? yes
: no) << "\n";
Circle ci;
type = "Figure";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";
type = "Ellipse";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";
type = "Circle";
std::cout << "is ci a " << type << "? " << (ci.IsType(type) ? yes
: no) << "\n";
}


I think you can start from here and improve this solution that is
somewhat messy. The concept is to implement some sort of recursion on
the function calls based on the templates arguments. With multiple
inheritance it won't work due to ambiguities... maybe it can be
improved.


Thanks Zeppe.

You're thinking creatively :)

But to be honnest, the work that i should do to implement this with
templates is much more than the work i just wanted to spare out by
"automatically" refering to the direct base class.

So, for now, i think i'll stick with explicitly writing the
'BaseClass::' thing all the time...

And i'll think your idea over.


To be honnest, the more i think about this, the more i'm surprised that
this is not in the C++ standard.

Being able to refer to the first parent base class in an abstract way
(e.g. this->_bass::foo or ((_base)this)->foo) definitely improves an OO
construction!

If you change the class hierarchy, now you may have to update all
references to the parent base class manually!!
 
Z

zeppe

Jo said:
To be honnest, the more i think about this, the more i'm surprised that
this is not in the C++ standard.

Being able to refer to the first parent base class in an abstract way
(e.g. this->_bass::foo or ((_base)this)->foo) definitely improves an OO
construction!

As I told you, such a construct would be too specific for a problem, it
would create problem with multiple inheritance, and it could be
replicated with a little template. In my view, the biggest problem with
your construct is that it should refer to the _first_ parent in the
hierarchy. Why the first? I think there is no such a strong concept of
first parent in c++ that can justify such an operator.
If you change the class hierarchy, now you may have to update all
references to the parent base class manually!!

Not with the method that i suggested you. If you don't want to implement
it, it's another story ;)

Anyway, probably you won't change the class hierarchy so often...

Regards,

Zeppe
 
J

Jo

zeppe said:
As I told you, such a construct would be too specific for a problem,
it would create problem with multiple inheritance, and it could be
replicated with a little template. In my view, the biggest problem
with your construct is that it should refer to the _first_ parent in
the hierarchy. Why the first? I think there is no such a strong
concept of first parent in c++ that can justify such an operator.


Just to be clear: with the first parent class i mean the class of which
explicitly is derived from. I don't mean the root base class.

The possible ambiguity in certain situations (e.g. multiple inheritance)
is not a big problem.

It's at the same problematic level as having ambiguous overloaded
functions: the compiler warns you, and you resolve it. Not a big problem.

I would suggest something analog here.
Not with the method that i suggested you. If you don't want to
implement it, it's another story ;)


Hey Zeppe, i believe it could be a nice technical solution, definitely
creative!

But the bad thing with templates is that they make the code harder to
read, more complex, and that's something i always try to avoid.

Keeping things as simple as possible. (but using complexity where really
necessary)

Anyway, i did not yet decide wether or not to use your method, i'll give
it some further thought...
Anyway, probably you won't change the class hierarchy so often...


Mmm, ... not sure about that.

And it's also about the OO principle of encapsulation: being able to
refer to the immediate base class of a class in a generic way would make
things more abstract, while constructively OK.

Anyway, if it's not in the syntax, then i'll have to live with it.
Nothing is perfect.

Thanks again,

Jo
 

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,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top