473,387 Members | 1,517 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

any alternatives to (lack of) virtual static functions?

Hello,
I searched for an answer to my question and found similar posts,
but none that quite addressed the issue I am trying to resolve.
Essentially, it seems like I need something like a virtual static
function (which I know is illegal), but, is there a way to provide
something similar? The class that is the target of my inquiry is a
template class that interfaces to one of several derived classes
through a pointer to a base class. The specific derived class that is
interfaced to depends on the template parameter provided. However, in
a few cases, I need to call a static (class) function associated with
the derived class when an objects of that class may not exist. Two
possibilities I have come up with are to 1) pass the static function
of the dervied class to the target class as a callback function or 2)
add the interface to the abstract base class, remove the static
designation of the function in the derived class, and use a half-
initialized object (ughh!) to access the function through a pointer to
the base class. Is there a better, more elegant way to do this?

Thanks,
Carl
Code example below.
template <typename T>
class Base
{
public:
// illegal to declare a virtual static function here
virtual void func1(T& a) = 0;
virtual void func2(T& b) = 0;
// ...

};
class Derived1 : public Base<int>
{
public:
static void Derived1Func(int& x); // type T is int in this case
void func1(int& a);
void func2(int& b);
// ...
};
class XyzType
{
XyzType() {}
~XyzType() {}
};
class Derived2 : public Base<XyzType>
{
public:
static void Derived2Func(XyzType& x); // type T is XyzType here
void func1(int& a);
void func2(int& b);
// ...
};
template <typename T>
class Target
{
void aFunc(Base<T*ptr);
void bFunc(Base<T*ptr);
// ...
};
template <typename T>
void Target<T>::aFunc(Base<T*ptr)
{
T aT;

ptr->func1(T& aT); // great, works fine

};
template <typename T>
void Target<T>::bFunc(Base<T*ptr)
{

// now here I need to get a handle on Derived1Func or Derived2Func
// ... or DerivedNFunc depending on the T parameter, or some other
// parameter if necessary. But I cannot call any of them directly
because
// this class primarily uses an interface to reference the specific
derived
// class (and does not know or care which derived class it is)
}

Thanks,
Carl
Dec 13 '07 #1
10 1434
carlm wrote:
>
[...]
>
template <typename T>
void Target<T>::bFunc(Base<T*ptr)
{
// now here I need to get a handle on Derived1Func or Derived2Func
// ... or DerivedNFunc depending on the T parameter, or some other
// parameter if necessary. But I cannot call any of them directly
because
// this class primarily uses an interface to reference the specific
derived
// class (and does not know or care which derived class it is)
}
Specialize it:

template <>
void Target<int>::bFunc(Base<int*ptr)
{
// ptr must be Derived1, in your specific case, cast it
Derived1 *p1 = (Derived1 *) ptr; // or use dynamic_cast...
p1->Derived1Func(...); // call the static function
}

template <>
void Target<XyzType>::bFunc(Base<XyzType*ptr)
{
// ptr must be Derived2, cast it
Derived2 *p2 = (Derived2*) ptr;
p2->Derived2Func(...);
}

Dec 13 '07 #2
template <typename T>
void Target<T>::bFunc(Base<T*ptr)
{

// now here I need to get a handle on Derived1Func or Derived2Func
// ... or DerivedNFunc depending on the T parameter, or some other
// parameter if necessary. But I cannot call any of them directly
because
// this class primarily uses an interface to reference the specific
derived
// class (and does not know or care which derived class it is)
Your problem is that T doesn't uniquely determine the most derived class,
i.e. it is permissible to have:

class Derived1 : Base<int{};
class Derived2 : Base<int{}; // same T

If you add a template parameter for the true type, you can call its static
members.

template <typename T>
template <typename D>
void Target<T>::bFunc(D* dptr)
{
Base<T*ptr = static_cast<Base<T>*>(dptr);

...

D::StaticFunction(); // function called varies with different D, unlike
generics in other languages
}

You can't have virtual dispatch without an object because virtual dispatch
depends on the runtime type of the object, no object... no runtime type.

Another option is to have a structure of function pointers, filled in for
each type. Then a pointer to this structure can be passed around, or a
virtual function in the interface can return it. This is essentially how
virtual calls work to begin with, except that the C++ virtual syntax doesn't
let you refer to the v-table and pass it around independent of an object.
Dec 13 '07 #3
>
Specialize it:

template <>
void Target<int>::bFunc(Base<int*ptr)
{
// ptr must be Derived1, in your specific case, cast it
Derived1 *p1 = (Derived1 *) ptr; // or use dynamic_cast...
p1->Derived1Func(...); // call the static function
You don't (or shouldn't) call static functions using an object instance,
it's misleading at best.

Type::Member() is the correct way to refer to a static function.

}

Dec 13 '07 #4
Ben Voigt [C++ MVP] wrote:
>Specialize it:

template <>
void Target<int>::bFunc(Base<int*ptr)
{
// ptr must be Derived1, in your specific case, cast it
Derived1 *p1 = (Derived1 *) ptr; // or use dynamic_cast...
p1->Derived1Func(...); // call the static function

You don't (or shouldn't) call static functions using an object instance,
it's misleading at best.

Type::Member() is the correct way to refer to a static function.
Ben:

ISTR that it is allowed by VC, but not by the C++ standard.

--
David Wilkinson
Visual C++ MVP
Dec 13 '07 #5
"Ben Voigt [C++ MVP]" wrote:
template <typename T>
void Target<T>::bFunc(Base<T*ptr)
{

// now here I need to get a handle on Derived1Func or Derived2Func
// ... or DerivedNFunc depending on the T parameter, or some other
// parameter if necessary. But I cannot call any of them directly
because
// this class primarily uses an interface to reference the specific
derived
// class (and does not know or care which derived class it is)

Your problem is that T doesn't uniquely determine the most derived class,
i.e. it is permissible to have:

class Derived1 : Base<int{};
class Derived2 : Base<int{}; // same T
Not following you here. Each of the derived classes inherits from the
abstract template class by providing a different type for the template
parameter and then overriding the corresponding pure virtual functions. This
seems right to me (and it compiles and runs as well).
If you add a template parameter for the true type, you can call its static
members.

template <typename T>
template <typename D>
void Target<T>::bFunc(D* dptr)
{
Base<T*ptr = static_cast<Base<T>*>(dptr);

...

D::StaticFunction(); // function called varies with different D, unlike
generics in other languages
}
Yes, this seems helpful and more obvious than I realized. Here is what I tried
and it worked with my cooked up example:

template <typename T, typename D>
void Target<T,D>::aFunc(Base<T*ptr)
{
T aT = 0;

ptr->func1(aT);
ptr->func2(aT);
D::StaticFunc(aT);
};
template <typename T, typename D>
void Target<T,D>::bFunc(Base<T*ptr) // ptr is an out parameter here
{
T aT = 0;

D::StaticFunc(aT);
};
The only thing that I do not like about this solution is that there is no
general declaration for D:StaticFunc() here. It is sort of implicit by the
way it is called in the Target class.
>
You can't have virtual dispatch without an object because virtual dispatch
depends on the runtime type of the object, no object... no runtime type.
Yes, I understand that.
Another option is to have a structure of function pointers, filled in for
each type. Then a pointer to this structure can be passed around, or a
virtual function in the interface can return it. This is essentially how
virtual calls work to begin with, except that the C++ virtual syntax doesn't
let you refer to the v-table and pass it around independent of an object.
I like the solution proposed above much better.
Thanks,
Carl
Dec 13 '07 #6
Your problem is that T doesn't uniquely determine the most derived class,
i.e. it is permissible to have:

class Derived1 : Base<int{};
class Derived2 : Base<int{}; // same T

Not following you here. Each of the derived classes inherits from the
abstract template class by providing a different type for the template
parameter and then overriding the corresponding pure virtual functions. This
seems right to me (and it compiles and runs as well).
Oh, I see what might have confused the issue. I made a mistake (at least
one!) in my example code. For Derived2, I should have provided:

class Derived2 : public Base<XyzType>
{
public:
static void Derived2Func(XyzType& x); // type T is XyzType here
void func1(XyzType& a);
void func2(XyzType& b);
// ...
};

I had ints in func1() and func2() previously. Sorry about that (the compiler
let me get away with it).

Dec 13 '07 #7

"carlm" <se*******@community.nospamwrote in message
news:EE**********************************@microsof t.com...
"Ben Voigt [C++ MVP]" wrote:
template <typename T>
void Target<T>::bFunc(Base<T*ptr)
{

// now here I need to get a handle on Derived1Func or
Derived2Func
// ... or DerivedNFunc depending on the T parameter, or some
other
// parameter if necessary. But I cannot call any of them directly
because
// this class primarily uses an interface to reference the
specific
derived
// class (and does not know or care which derived class it is)

Your problem is that T doesn't uniquely determine the most derived class,
i.e. it is permissible to have:

class Derived1 : Base<int{};
class Derived2 : Base<int{}; // same T

Not following you here. Each of the derived classes inherits from the
abstract template class by providing a different type for the template
parameter and then overriding the corresponding pure virtual functions.
This
seems right to me (and it compiles and runs as well).
Yes it does. But now knowing that T is int doesn't tell you that D is
Derived1...
>
>If you add a template parameter for the true type, you can call its
static
members.

template <typename T>
template <typename D>
void Target<T>::bFunc(D* dptr)
{
Base<T*ptr = static_cast<Base<T>*>(dptr);

...

D::StaticFunction(); // function called varies with different D,
unlike
generics in other languages
}

Yes, this seems helpful and more obvious than I realized. Here is what I
tried
and it worked with my cooked up example:

template <typename T, typename D>
void Target<T,D>::aFunc(Base<T*ptr)
{
T aT = 0;

ptr->func1(aT);
ptr->func2(aT);
D::StaticFunc(aT);
};
template <typename T, typename D>
void Target<T,D>::bFunc(Base<T*ptr) // ptr is an out parameter here
{
T aT = 0;

D::StaticFunc(aT);
};
The only thing that I do not like about this solution is that there is no
general declaration for D:StaticFunc() here. It is sort of implicit by the
way it is called in the Target class.
C++0x will introduce "concepts" which place constraints on template type
arguments, including static members.
Dec 13 '07 #8
carlm wrote:
Oh, I see what might have confused the issue. I made a mistake (at least
one!) in my example code. For Derived2, I should have provided:

class Derived2 : public Base<XyzType>
{
public:
static void Derived2Func(XyzType& x); // type T is XyzType here
void func1(XyzType& a);
void func2(XyzType& b);
// ...
};

I had ints in func1() and func2() previously. Sorry about that (the compiler
let me get away with it).
carlm:

The compiler let you get away with it because you were just declaring
two non-virtual functions (taking an int parameter). This is allowed,
though not a good idea, and some compilers will warn you that you are
hiding the base class functions of the same names.

--
David Wilkinson
Visual C++ MVP
Dec 13 '07 #9
Not following you here. Each of the derived classes inherits from the
abstract template class by providing a different type for the template
parameter and then overriding the corresponding pure virtual functions.
This
seems right to me (and it compiles and runs as well).

Yes it does. But now knowing that T is int doesn't tell you that D is
Derived1...
That's true and a good point. It seems, however, no matter how things are
arranged, either as your original proposal:
>template <typename T>
template <typename D>
void Target<T>::bFunc(D* dptr)
{
Base<T*ptr = static_cast<Base<T>*>(dptr);

...

D::StaticFunction(); // function called varies with different D,
unlike
generics in other languages
}
or as in my interpretation of it:
template <typename T, typename D>
void Target<T,D>::aFunc(Base<T*ptr)
{
T aT = 0;

ptr->func1(aT);
ptr->func2(aT);
D::StaticFunc(aT);
};
two template parameters are needed--unless there is some additional template
magic that can be brought to bear on the issue. In any case, I believe I have
a decent solution now, at least one that is superior to passing in a callback
function. So, I will proceed with this.

Ben, David, "count0", thank you very much for your assistance on this matter.

Dec 14 '07 #10

"carlm" <se*******@community.nospamwrote in message
news:C5**********************************@microsof t.com...
>
Not following you here. Each of the derived classes inherits from the
abstract template class by providing a different type for the template
parameter and then overriding the corresponding pure virtual functions.
This
seems right to me (and it compiles and runs as well).

Yes it does. But now knowing that T is int doesn't tell you that D is
Derived1...

That's true and a good point. It seems, however, no matter how things are
arranged, either as your original proposal:
>>template <typename T>
template <typename D>
void Target<T>::bFunc(D* dptr)
{
Base<T*ptr = static_cast<Base<T>*>(dptr);

...

D::StaticFunction(); // function called varies with different D,
unlike
generics in other languages
}

or as in my interpretation of it:
>template <typename T, typename D>
void Target<T,D>::aFunc(Base<T*ptr)
{
T aT = 0;

ptr->func1(aT);
ptr->func2(aT);
D::StaticFunc(aT);
};

two template parameters are needed--unless there is some additional
template
magic that can be brought to bear on the issue. In any case, I believe I
have
a decent solution now, at least one that is superior to passing in a
callback
function. So, I will proceed with this.
While T does not uniquely determine D, the converse is unique... you can
eliminate the redundancy thus:

template <typename T1>
class Base
{
public:
typedef T1 T;
};

template <typename D>
void aFunc(D *ptr)
// or aFunc(typename Base<D::T>* ptr)
{
typename D::T aT = 0;

ptr->func1(aT);
ptr->func2(aT);
D::StaticFunc(aT);
};
>
Ben, David, "count0", thank you very much for your assistance on this
matter.
Dec 14 '07 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Simon Elliott | last post by:
If I have a base class and several possible derived classes, and I have a pointer to the base class, what's the best way of determining whether the pointer is pointing to a base class or to a...
6
by: Dumitru Sipos | last post by:
Hello everybody! is there possible to have a function that is both static and virtual? Dumi.
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
43
by: Steven T. Hatton | last post by:
Now that I have a better grasp of the scope and capabilities of the C++ Standard Library, I understand that products such as Qt actually provide much of the same functionality through their own...
4
by: Ian Malone | last post by:
I have a class which looks like this: class reco { public: int height, width; double beta; double mu; simple_d_field estimate; simple_d_field auxiliary;
15
by: Philipp | last post by:
Hello I don't exactly understand why there are no static virtual functions. I would have liked something like this: class Base{ static virtual std::string getName(){ return "Base"; } }
7
by: desktop | last post by:
This page: http://www.eptacom.net/pubblicazioni/pub_eng/mdisp.html start with the line: "Virtual functions allow polymorphism on a single argument". What does that exactly mean? I guess it...
6
by: greek_bill | last post by:
Hi, I'm interested in developing an application that needs to run on more than one operating system. Naturally, a lot of the code will be shared between the various OSs, with OS specific...
17
by: Jess | last post by:
Hello, If I have a class that has virtual but non-pure declarations, like class A{ virtual void f(); }; Then is A still an abstract class? Do I have to have "virtual void f() = 0;"...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.