简体   繁体   中英

Why doesn't C++ allow adding new methods to classes?

It seems like a rather arbitrary limitation. Aren't regular methods just like C functions with a parameter that points to the instance?

If so I don't see why adding new methods should force me to recompile the rest of my class. Why not allow adding methods via a separate amendment header and a separate amendment implementation.

Consider this example

  // in some header

  struct X
  {
      float func(float);
  };

  // and in another source file

  void caller()
  {
       X x;
       std::cout << x.func(2);     // will call X:func(float)
  }

Now let's say we decide to add a new version of func() that accepts an int .

        // in some header

  struct X
  {
      float func(float);
      void func(int);
  };

  // and in another source file

  void caller()
  {
       X x;
       std::cout << x.func(2);
  }

If the caller() function is not recompiled, there is no way to register that the function it is calling has changed - it will keep calling X::func(float) in the build.

Then - possibly months (or in large systems, years) after the fact - another developer makes a completely unrelated change to one of the functions in the same source file as caller() . Hence that source file gets rebuilt ... finally. Suddenly that person finds that caller() won't compile - with error messages that have nothing whatsoever to do with changes of code he or she is implementing.

All this happens when the offender - the programmer who introduced the new member functions but didn't trigger a recompile and rebuild - is nowhere to be seen.

The developer left behind is left to fix the mess. With no information about what actually caused the problem, why it was working yesterday but not today, no real clue as to how to fix it properly .... but still the one who will be held responsible.

This is just one of many problems that the "arbitrary limitation" in C++ will prevent.

A couple of things comes to my mind. On one hand you need to declare the scope of the method, I presume that's the reason why you are allowed to add new operators in the way that you are suggesting.

On the other hand, you have a problem with inheritance. The compiler need to know all the virtual methods in order to include them in the vtable.

As deviantfan said, it's no real problem really (assuming you want to add a regular (nonvirtual) method).

$ for file in X.hh X.cc X-1.hh X-1.cc main.cc; do echo -e "\n//--------------//$file"; cat "$file";  done                                                                                                                           

//--------------//X.hh
//X.hh
struct X {
   int foo(int);
};

//--------------//X.cc
//X.cc (available as X.o)
#include "X.hh"
int X::foo(int a){ return a+1; }

//--------------//X-1.hh
//X-1.hh
//copy X.hh and amend it
struct X {
   int foo(int);
   int bar(int);
};

//--------------//X-1.cc
//X-1.cc
#include "X-1.hh"
int X::bar(int a){ return a+2; }

//--------------//main.cc
//main.cc
#include "X-1.hh"
//^the latest definition
#include <iostream>
int main(){
  using namespace std;
  X x;
  cout << x.foo(1) << endl;
  cout << x.bar(1) << endl;

And now the building part:

$ make {X,X-1,main}.o
$ g++ {X,X-1,main}.o   #links correctly!
$ ./a.out
2
3

Works even if the methods access class/struct variables.

TL;DR:

If you use a build system that uses depend files that track #include s, you can make --assume-old a header (or touch --date='10 minutes ago' changed_header.hh ) that only changed by means of trivial method additions (no overloads or virtuals), as all old object files that depended on the old subset of the class's instance methods won't need to be recompiled.

Also, as Raphael Miedl points out, there's a proposal for a http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf that basically allows freestanding functions to be invoked via the dot syntax, so that's basically tantamount to reopening a class for trivial function additions.

Overloaded functions aren't really a problem as you would always #include a particular representation of a class (or the same class + a particular set of dot-syntax mappable free-standing functions) and you could have different versions of the same class (equivalent to having one class + different sets of dot-syntax mappable free-standing functions). (unlike virtual functions, because of vtables and vtable pointers in object instances).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM