2015-06-28 74 views
3

这似乎是一个相当武断的限制。 像C函数那样的常规方法不是指向实例的参数吗?为什么C++不允许向类中添加新的方法?

如果是这样,我不明白为什么添加新方法应该强制我重新编译我的课程的其余部分。为什么不允许通过单独的修订头和单独的修改实现来添加方法。

+2

TBH向类中添加方法应该是一个相对罕见的事件(假设您的项目有* design *阶段)。 – Galik

+2

@Galik真的,但他似乎在问一个关于C++技术特性的问题,而不是它的设计理念。 –

+3

这听起来像只是等待发生的ODR违规行为。例如。重载分辨率在看到额外方法的转换单元和不转换单元之间的工作方式会有所不同。 –

回答

1

我想起了几件事情。一方面,您需要声明方法的范围,我认为这就是允许您按照您的建议添加新操作符的原因。

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

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()的新版本接受一个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()相同的源文件中的某个函数完全无关的更改。因此,源文件得到重建...最后。突然间,那个人发现caller()将不能编译 - 错误消息与他或她正在执行的代码更改没有任何关系。

所有这些都发生在违规者 - 引入新成员函数但没有触发重新编译和重建的程序员 - 无处可见时。

留下的开发人员留下来解决这个烂摊子。由于没有关于究竟是什么导致问题的信息,为什么它昨天工作,但不是今天工作,没有真正的线索,如何妥善解决它......但仍然是谁将负责。

这只是C++中“任意限制”会阻止的许多问题之一。

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 s个文件构建系统,可以make --assume-old一个报头(或touch --date='10 minutes ago' changed_header.hh) ),因为所有依赖于类实例方法的旧子集的旧对象文件都不需要重新编译。

此外,拉斐尔Miedl指出,有一个http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4474.pdf ,基本上允许通过点语法来调用独立职能的建议,所以这基本上等同于重新打开类琐碎的功能补充。

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

相关问题