0

My math library heavily uses interfaces. It works in a way that I have an interface, for example IVector, and then child classes can derive/implement it. The reason for that is that all vectors need to be able to take a dot product with another vector, and I don't want to forget it for some reason, so it's good to have it there. Those are not exactly interfaces, though. For example, the implementation for getting the magnitude of a vector is not specific to each vector struct, so I just put it in IVector. I also have a Vector namespaces that calls functions from the IVector interface, so I will also be able to do Vector::Dot(a, b), instead of a.Dot(b).

That setup works really well, but there is a big problem: The size of the structs implementing the interfaces is bigger. After doing some testing, I found out the reason for that is the pure virtual functions:

#include <iostream>
using namespace std;

#define PRINT(thing) cout << thing << endl

struct A
{
    virtual void F() = 0;
};

class B final : public A
{

};

class C
{
    void F()
    {

    }
};

class D : public C
{

};


void main()
{
    PRINT(sizeof(A)); // 4
    PRINT(sizeof(B)); // 4
    PRINT(sizeof(C)); // 1
    PRINT(sizeof(D)); // 1
    cin.get();
}

What I assumed is that the cause for that is the vpointer, but I am not sure.

But even if it makes sense that it happens, why do struct sizes not get any bigger when implementing interfaces in C#? That's a test I ran (not that I get the same result with Marshal.SizeOf for Stuff, but it doesn't work with the interfaces):

using System;
using DotNetCross.Memory;

interface IStuff
{
    void DoStuff();
}

interface IPlsStop : IStuff
{
    void Whatevah();
}

struct Stuff : IPlsStop
{
    public void DoStuff()
    {

    }

    public void Whatevah()
    {

    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Unsafe.SizeOf<Stuff>());    // 1
        Console.WriteLine(Unsafe.SizeOf<IStuff>());   // 8
        Console.WriteLine(Unsafe.SizeOf<IPlsStop>()); // 8

        Console.ReadKey();
    }
}

I thought interfaces were just sugar for pure abstract classes, but apparently they are not. I assume the size of the interfaces themselves is larger because they are reference types.

So why do C# interfaces not take more memory while C++ pure-virtual functions do take up more memory?

That problem causes me way too many problems, and I must fix it. The thing I want to know the most is what I can do to make C# like interfaces in C++ (so I can implement them without the class becoming larger).

Or Aviram
  • 39
  • 4
  • 6
    Why are you surprised that the behavior of objects in C++ and C# differs? They are completely different languages with different specifications and implementations. In any case [yes the change in `sizeof` is because of the virtual function(s)](https://stackoverflow.com/questions/4766323/how-to-determine-sizeof-class-with-virtual-functions) – Cory Kramer Sep 27 '17 at 14:21
  • 1
    In C++, the size of structures - in general terms - depends on specifics of how the compiler is implemented. According to the C++ standard, it is implementation defined so different compilers can - and practically will - give different results. You've claimed that the different sizes cause you "way too many problems" - the only way that can happen is if you write code that relies on (or makes assumptions about) objects having particular sizes. And, except in some very special cases, that is a sign of poor program design. – Peter Sep 27 '17 at 14:29
  • Why don't you make your math operations using data on attributes of each class, instead of worrying with the size in bits of the class that holds the data you need? – Leonardo Alves Machado Sep 27 '17 at 14:29
  • 1
    "My math library heavily uses interfaces." maybe thats the problem you have to fix. Virtuals taking space is not a "problem" but just a fact. Dont get inspired by C# (or java?) when you write C++ – 463035818_is_not_an_ai Sep 27 '17 at 14:30
  • 4
    `#define PRINT(thing) cout << thing << endl`, you should use (inline) function instead of MACRO. – Jarod42 Sep 27 '17 at 14:32
  • 1
    Does it even make sense to try to take the size of a C# interface - it is a definition of methods/properties/etc that a class or struct implementing it must have. You cannot create an instance of an interface - so it's size is meaningless. You say that the size issue causes you problems - what problems exactly. – PaulF Sep 27 '17 at 14:38
  • @Peter Why is depending on the size a bad design? I have it so my 2 by 2 matrix has a union with a float[4] and a float[2][2], and I have a GetRow method returning a reference. What I wanted to do is just "*(Vector2D*)(elements2x2[index])". I don't see anything wrong with depending on the size. – Or Aviram Sep 27 '17 at 14:43
  • @tobi303 Maybe you are right. The problem is that it just makes my life so much easier. I will stop using virtual functions if I find out it just has to be like that, but is there a way to do what I did in C#, or I just have to not use it? – Or Aviram Sep 27 '17 at 14:43
  • if you use more templates instead you can make your life harder, but also more fun ;) why build a hierachy of interfaces when you can use ducktyping? – 463035818_is_not_an_ai Sep 27 '17 at 14:59
  • @Or Aviram - your example in comment (equivalences between the size of arrays (e.g. a `float [4]` is the same size as a `float[2][2]` - for a given compiler) is one of the few cases where that works. That is a special case - there are many more cases where you CANNOT rely on equivalences of sizes, and sizes of data structures - which is what your original question is about - is one of the many cases where you cannot safely rely on consistent sizes. – Peter Sep 27 '17 at 15:03
  • I think this would be a very good question if you asked how it is possible to have a `SizeOf` of `1` in the C# version, given that it has interface methods. It feels like the type information is not part of the object "size" in C#. – rustyx Sep 27 '17 at 15:16
  • @Peter But can't I just **not** rely on the size wherever it won't work? Is there a problem with using it at all? – Or Aviram Sep 27 '17 at 15:21
  • It does not make much sense to use virtual functions for a math library as it will make your code slower... – Phil1970 Sep 27 '17 at 16:22
  • @Phil1970 Why would it make my code slower? Since you will most likely make objects, and not use pointers, the part where you go to the correct implementation of the function doesn't happen (since the compiler can figure out which version to call). But that memory thing and tobi303's idea (which seems pretty good, so I am trying to implement it now) will probably make me stop using them anyways. – Or Aviram Sep 27 '17 at 16:27
  • @OrAviram - sure. But your original question was because you were seeking to rely on sizes when there is no guarantee. – Peter Sep 28 '17 at 08:46

1 Answers1

1

The marshal size of a C# class describes the amount of bytes needed to store it. That is independent of the interface.

The sizeof a C++ class describes the amount of memory needed in order to implement it.

These are 2 different concepts, and explain the difference you are observing

mksteve
  • 12,614
  • 3
  • 28
  • 50