为什么C ++不允许向类添加新方法?

时间:2015-06-28 01:15:51

标签: c++

这似乎是一个相当随意的限制。 常规方法不像C函数那样带有指向实例的参数吗?

如果是这样,我不明白为什么添加新方法会迫使我重新编译我的其余课程。为什么不允许通过单独的修订标题和单独的修订实施来添加方法。

3 个答案:

答案 0 :(得分:5)

考虑这个例子

  // 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)
  }

现在让我们说我们决定添加一个接受func()的{​​{1}}新版本。

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); } 函数,则无法注册它正在调用的函数已更改 - 它将继续在构建中调用caller()

然后 - 可能在几个月之后(或在大型系统中,数年) - 另一个开发人员对与X::func(float)相同的源文件中的一个函数进行完全无关的更改。因此,源文件最终得到重建。突然间,那个人发现caller()不会编译 - 错误信息与他或她正在实施的代码更改没有任何关系。

所有这一切都发生在罪犯 - 介绍新成员功能但未触发重新编译和重建的程序员 - 无处可见时。

留下的开发人员留下来解决这个烂摊子。由于没有关于实际导致问题的原因的信息,为什么它在昨天工作但不是今天,没有真正的线索如何正确地解决它......但仍然是负责任的人。

这只是&#34;任意限制&#34;的许多问题之一。在C ++中会阻止。

答案 1 :(得分:1)

我想到了几件事。一方面,你需要声明方法的范围,我认为这是你被允许以你建议的方式添加新运算符的原因。

另一方面,你有继承问题。编译器需要知道所有虚拟方法,以便将它们包含在vtable中。

答案 2 :(得分:0)

正如deviantfan所说,它确实没有真正的问题(假设您想要添加常规(非虚拟)方法)。

$ 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;

现在是建筑部分:

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

即使方法访问类/结构变量也可以工作。

TL; DR:

如果您使用的构建系统使用跟踪#include的依赖文件,您可以make --assume-old仅通过添加简单方法更改的标头(或touch --date='10 minutes ago' changed_header.hh)(否)重载或虚拟),因为所有依赖于类实例方法的旧子集的旧目标文件都不需要重新编译。

此外,正如Raphael Miedl所指出的那样,有http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf提案 这基本上允许通过点语法调用独立函数,因此这基本上等于重新打开一个类来添加琐碎的函数。

重载函数不是一个真正的问题,因为你总是#include一个类的特定表示(或同一个类+一组特定的点语法可映射的独立函数),你可以具有相同类的不同版本(相当于具有一个类+不同的点语法可映射的独立函数集)。 (与虚函数不同,因为对象实例中的vtable和vtable指针)。