Home > Blockchain >  C allows instantiation of objects with just function declaration
C allows instantiation of objects with just function declaration

Time:12-19

Simple code below.

class Base{
public:
    int fcn();
};

int main() {
   Base b; // clause 1
}

Why does this compile? Clause 1 creates a Base instance but the function fcn() is never defined.

CodePudding user response:

The reason Base b; is not a compiler error is because the compiler cannot know in general if a definition is missing.

The code you posted might be the complete translation unit while the definition is in a different translation unit. Only the linker will issue an error when a definition is needed (eg to call the fucntion) but no definition can be found.


There are actually many cases where one wants something to be declared but not defined (or only conditionally defined). It follows two examples.


Suppose you have a method with a double argument and you want to prevent a user to call it with an int. Implicit conversions can be annoying, implcicit conversion of fundamental types even more. One can do something like this:

struct foo {
    void do_something(double) {}
};
struct bar {
    void do_something(double) {}
    void do_something(int);      // no definition !!
};
    
int main()
{
    foo{}.do_something(1);
    bar{}.do_something(1);
}

foo::do_something(double) can be called with an int. On the other hand bar::do_something(double) has to compete with bar::do_something(int) in overload resolution and bar{}.do_something(1); results in a linker error.

Note that here are nicer ways to get a nicer compiler error message (= delete since C 11). However, the point is: As long as you are only calling bar::do_something with a double all is fine. No error. And no error to be expected. It works and is completely valid C .


Another example is tag types used to distinguish between different instantiations of a template:

struct tag1;   // no definition !!
struct tag2;   // no defniition !!

template <typename T> struct foo;
template <> struct foo<tag1> { /* something */ };
template <> struct foo<tag2> { /* something else */ };

int main() {
    foo<tag1> a;
    foo<tag2> b;
}

This is completely fine, because the template does nothing that would require its argument to be a complete type. Using types merely to tag instantiations of a template or to select an overload is a common technique and sometimes all you need for the tag is a declaration.

Addmittetly this is different from your example, because its a whole class definition missing and nowhere an instance of the classes is created. Though I would put it in the same bag of: Useful to have a declaration without definition.

  • Related