Alternative to C++ Static Virtual Methods

Alternative to c++ static virtual methods

You can make Base be a class template that takes its function pointers from its template argument:

extern "C" {
struct CStruct
{
void (*funA)(int, char const*);
int (*funB)(void);
};
}

template <typename T>
class Base
{
public:
CStruct myStruct;
void FillPointers() {
myStruct.funA = &T::myFunA;
myStruct.funB = &T::myFunB;
}
Base() {
FillPointers();
}
};

Then, define your derived classes to descend from an instantiation of Base using each derived class as the template argument:

class Derived1: public Base<Derived1>
{
public:
static void myFunA(int, char const*) { }
static int myFunB() { return 0; }
};

class Derived2: public Base<Derived2>
{
public:
static void myFunA(int, char const*) { }
static int myFunB() { return 1; }
};

int main() {
Derived1 d1;
d1.myStruct.funA(0, 0);
d1.myStruct.funB();
Derived2 d2;
d2.myStruct.funA(0, 0);
d2.myStruct.funB();
}

That technique is known as the curiously recurring template pattern. If you neglect to implement one of the functions in a derived class, or if you change the function signature, you'll get a compilation error, which is exactly what you'd expect to get if you neglected to implement one of the pure virtual functions from your original plan.

The consequence of this technique, however, is that Derived1 and Derived2 do not have a common base class. The two instantiations of Base<> are not related in any way, as far as the type system is concerned. If you need them to be related, then you can introduce another class to serve as the base for the template, and then put the common things there:

class RealBase
{
public:
CStruct myStruct;
};

template <typename T>
class Base: public RealBase
{
// ...
};

int main()
RealBase* b;
Derived1 d1;
b = &d1;
b->myStruct.funA(0, 0);
b->myStruct.funB();
Derived2 d2;
b = &d2;
b->myStruct.funA(0, 0);
b->myStruct.funB();
}

Beware: Static member functions are not necessarily compatible with ordinary function pointers. In my experience, if the compiler accepts the assignment statements shown above, then you can at least be confident that they're compatible for that compiler. This code isn't portable, but if it works on all the platforms you need to support, then you might consider it "portable enough."

Alternative to virtual static functions in c++?

Calling a virtual function without an object is a contrasense,
since the resolution depends on the type of the object.
are cases where you might need to call the same function
dependant on the type of an object, or specifying the class
explicitly, without an object. This is easily handled by using
two functions, one static, and one virtual. (Typically, the
virtual one will just forward to the static.)

EDIT:

A simple example (from actual code):

#define DECLARE_CLASS_NAME(className)                               \
static char className() { return STRINGIZE(className); } \
virtual char* getClassName() { return className(); }

class Base
{
public:
DECLARE_CLASS_NAME(Base);
// ...
};

class Derived : public Base
{
public:
DECLARE_CLASS_NAME(Derived);
// ...
};

and so on, in all of the derived classes. This was used to
obtain the type names for serialization, for example:

std::string typeName = pObj->getClassName();

and also as a primitive RTTI (this was about 20 years ago):

if ( pObj->getClassName() == Derived::className() ) ...

(We had established the rule that the only way you could obtain
the name of a class was by using one of these functions. That
effectively internalized the names of the classes, and allowed
simple pointer comparisons to work. On the systems we were
working on then, this was important.)

C# Alternative to virtual static methods and static sub classes

This could serve your purpose, though I certainly would include some exception handling and accompany its implementation with a great deal of documentation as to why and how it works.

When the static constructor for Base is run (once) all assemblies that are currently loaded in the app domain are catalogued, selecting the types that derive from Base. Iterating over those, we run the static constructors. It is worth noting though, that this no longer guarantees the cctor for each implementation will be run exactly once, logic would have to be added to each of them to re-make that assertion. Moreover, types that are loaded after the cctor for Base has been run would not be initialized by calls to methods in Base

To simulate virtual methods, use the new keyword to hide the base method. You can call the base method by qualifying it with the declaring class's name (like in class B in the example)

using System;
using System.Linq;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
public class Base
{
static Base()
{
Console.WriteLine("Base cctor");

var thisType = typeof (Base);
var loadedTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes());
var derivations = loadedTypes.Where(thisType.IsAssignableFrom);

foreach(var derivation in derivations)
{
RuntimeHelpers.RunClassConstructor(derivation.TypeHandle);
}
}

public static void Foo()
{
Console.WriteLine("Bar");
}
}

public class A : Base
{
static A()
{
Console.WriteLine("A cctor");
}
}

public class B : Base
{
static B()
{
Console.WriteLine("B cctor");
}

public new static void Foo()
{
Console.WriteLine("Bar!!");
Base.Foo();
}
}

class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}

EDIT

Another option lies in the CRTP (or CRGP in the C# paradigm) or curiously recurring template (generic) parameter pattern

using System;
using System.Runtime.CompilerServices;

namespace ConsoleApplication6
{
public class Base<T>
where T : Base<T>
{
static Base()
{
RuntimeHelpers.RunClassConstructor(typeof (T).TypeHandle);
}

public static void Foo()
{
Console.WriteLine("Bar");
}
}

public class Base : Base<Base>
{
}

public class A : Base<A>
{
static A()
{
Console.WriteLine("A cctor");
}
}

public class B : Base<B>
{
static B()
{
Console.WriteLine("B cctor");
}

public new static void Foo()
{
Console.WriteLine("Bar!!");
Base<B>.Foo();
}
}

class Program
{
static void Main()
{
Console.WriteLine("A:");
A.Foo();
Console.WriteLine();
Console.WriteLine("B:");
B.Foo();
Console.WriteLine();
Console.WriteLine("Base:");
Base.Foo();
Console.ReadLine();
}
}
}

In this case, when we call a static method on A we're really calling it on Base<A> which is different than Base<B> or Base so we can actually determine how the method was called and run the appropriate cctor.

How to implement static virtual member function

One possible solution is CRTP with base class injection.

template <typename T, typename... Bases> 
struct CRTPFooInjector : Bases...
{
virtual void vfoo() { T::foo(); }
};

This is your injector template. It only implements the virtual version of foo, nothing else.

struct Base: CRTPFooInjector<Base>
{
static int foo() { std::cout << "Base::foo()" << std::endl; }
};

struct Der1 : CRTPFooInjector<Der1, Base>
{
static int foo() { std::cout << "Der1::foo()" << std::endl; }
};

struct Der2 : CRTPFooInjector<Der2, Base>
{
static int foo() { std::cout << "Der2::foo()" << std::endl; }
};

struct Der12 : CRTPFooInjector<Der12, Der1, Der2>
{
static int foo() { std::cout << "Der12::foo()" << std::endl; }
};

Now instead of your normal hierarchy Base <- Der1 <- Der12 you have a slightly different one Injector <- Base <- Injector <- Der1 <- Injector <- Der12, but this should be transparent for most users.

If you need to mix in some virtual base classes:

template <typename T>
struct Virtual : virtual T
{
};

struct Der1 : CRTPFooInjector<Der1, Virtual<Base>> ...

Alternative to calling a virtual method in C#

The problem lies in virtual set. Passing a value to the virtual property in the base class constructor will use overriden set instead base set. If overriden set relies on data in derived class, then you are in trouble, because constructor of derived class was not done yet.

If you are absolutely sure, that any subclass will not use any data of its state in overriden set, then you can initialize virtual properties in base class constructor. Consider adding an appropriate warning to the documentation.

If possible, try to create backing fields for each property and use them in base class contructor.

You can also postpone properties initialization to the derived class. To achieve that, create an initializing method in the base class that you invoke in constructor of derived class.

Why have virtual static members not been added as a feature of C++?

First, let's look at an invalid example of how static virtuals could look:

// WARNING: This does not compile !!!
class Base {
static virtual string toWhom() {
return "unknown";
}
static void sayHello() {
cout << "Hello, " << toWhom() << "!" << endl;
}
};
class World : public Base {
static virtual string toWhom() {
return "world";
}
};
class Everybody : public Base {
static virtual string toWhom() {
return "everybody";
}
};

This would let you do this:

// WARNING: This does not work !!!
Everybody::sayHello(); // Prints "Hello, everybody!"
World::sayHello(); // Prints "Hello, world!"

The problem, however, is that a dispatch like this would not be easy to implement without changing the way static functions are called in C++.

Recall that non-static member functions get this parameter implicitly. It is this parameter that carries information about virtual functions with it. When you call a static function, however, nothing is passed that would identify the current class (i.e. Hello vs. Everybody in the example above). There are no implicit arguments, hence no access to virtual functions.

Going back to the example above, consider what would happen when Base::sayHello calls toWhom(). It needs to have some context to make a decision on which of the three function should be called - i.e. Base::toWhom, World::toWhom, or Everybody::toWhom. Not only is this information missing, but there is also no existing mechanism in the language on which we could "piggyback" this functionality in a way similar to how a pointer to virtual functions is added to the data for the class.

Although it is true that this invocation mechanism could be changed, the authors of the language did not see compelling reasons for doing this.

Alternative/Suggestion for C++ Polymorphism With Virtual Function

From what I understand, you might use template, something similar to

template <typename Range, typename F>
auto f(const Range& r, F&& f)
{
std::vector<std::decay_t<decltype(f(*r.begin()))>> result;

result.reserve(r.size());
for (const auto& e : v) {
result.push_back(f(e));
}
return result;
}

class MeanCalculator
{
public:
float operator()(float x) const {
n++;
mean += (x - mean) / n;
return mean;
}
private:
std::size_t n = 0;
float mean = 0.0f;
};

class VarianceCalculator
{
public:
float operator()(float x) const {
n++;
// ...
}
private:
std::size_t n = 0;
//...
};

And then

std::vector<float> numbers = /*...*/;
auto means = f(numbers, MeanCalculator{});
auto variances = f(numbers, VarianceCalculator{});

Note: std::transform cannot be used as it doesn't guaranty in-order application of f.



Related Topics



Leave a reply



Submit