在C++编程中如何展示某些方法在一个类中还未被实现,以便向你的合作程序员传达这一信息

9

当你进行以下工作时,可以使用哪些方法:

  • 与其他几个程序员(例如1-3人)在小型C ++项目上一起工作,您使用单个存储库
  • 创建一个类,声明其方法
  • 还没有时间实现所有方法
  • 因为代码尚未实现而不想让其他程序员使用您的代码; 或者不想使用尚未实现的代码部分
  • 没有时间/可能告诉同事所有这些尚未实现的内容
  • 当您的同事使用您尚未实现的代码时,您希望他们立即意识到他们还不应该使用它-如果他们遇到错误,您不希望他们猜测出错的原因、寻找潜在的错误等。

你可以在方法存根中使用预处理器警告。 - asm
9
当你需要实现临时代码时,应该创建一个分支,在完成实现后再将其合并。 - Markos
@Markos:这不适合自上而下的开发。 - Alsk
7个回答

14

最简单的答案是告诉他们。在与一组人一起工作时,沟通至关重要。

更加全面(也可能是最好的)的选择是创建自己的分支以开发新功能,只有在完成后将其合并回主分支。

但是,如果你真的希望你的方法被实现在主源代码中,但不想让人们使用它们,请使用异常或断言来存根。


3
+1 表示确认。这是对于准确回答问题的最直接的回复。 - Akusete
断言/异常方式是一种通过代码而非口头/聊天交流的通信方式。在这种情况下,它应该优先于口头交流。否则呢?每次创建函数存根时,都必须通过会议或电话打扰同事,而大多数人甚至不会调用存根。 - Alsk
这样的代码应该很有效: assert(false && "未实现,请勿寻找错误!") - Fabio Fracassi
@Alsk,确实我打算让“告诉他们”广泛适用于各种形式的交流(电子邮件,评论等)。个人而言,我宁愿知道不要使用某个函数,因为这个事实已经被告知,而不是在编译/运行时尝试使用它,结果发现一开始就不应该使用。 - Cogwheel

10

我很喜欢.Net中的NotImplementedException这个概念。你可以轻松地定义自己的异常类,派生自std::exception,并将what覆盖为“未实现”。

它有以下优点:

  1. 易于搜索。
  2. 允许当前和依赖的代码编译。
  3. 可以执行到需要代码的那一点,此时会失败(并且您立即获得了一个演示需求的执行路径)。
  4. 当它失败时,除非您完全忽略异常,否则会失败到已知状态,而不是依赖于不可预测的状态。

8
你应该要么不提交代码,要么将其提交到开发分支中,这样即使你的计算机发生灾难性故障,代码也至少不再存在于你的机器上。
这就是我在工作中使用 git 存储库时所做的。我在一天结束时将我的工作推送到远程存储库(而不是主分支)。我的同事知道这些分支非常不稳定,除非他真的喜欢破碎的分支,否则不要轻易触碰。
Git 对于这种情况非常方便,其他具有便宜分支功能的 dvcs 也应该如此。如果在 SVN 或更糟糕的 CVS 中进行此操作,将会带来痛苦和折磨。

相信我,如果你没有版本控制,那么你会遭受更多的痛苦。即使是在NFS上使用RCS也比那好得多。(就像那种情况下你可以使用VSS一样,因为它们的可用性都差不多。) - Donal Fellows

7

我不会将其提交到代码库中。


4
个人认为最佳选择是,如果代码不可用,就不要在检查它之前提交它,直到它处于可用状态。如果他们无法使用它,也没有任何损失。或者使用分支后合并的方式。 - GManNickG

5

声明它,而不要实现它。当程序员调用未实现的代码部分时,链接器会发出警告,这对程序员来说是一个明显的打击。

class myClass
{
    int i;
public:
    void print(); //NOt yet implemented
    void display()
    {
        cout<<"I am implemented"<<endl;
    }
};

int main()
{
    myClass var;
    var.display();
    var.print(); // **This line gives the linking error and hints user at early stage.**
    return 0;
}

4

断言是最好的方法。不会终止程序的断言更好,这样同事就可以继续测试他的代码,而不会被您的函数存根阻塞,并且他可以完全了解哪些功能尚未实现。

如果您的IDE不支持智能断言或持久性断点,则可以使用以下简单实现(c ++):

#ifdef _DEBUG
    // 0xCC - int 3 - breakpoint
    // 0x90 - nop? 
    #define DebugInt3 __emit__(0x90CC)
    #define DEBUG_ASSERT(expr) ((expr)? ((void)0): (DebugInt3) )
#else
    #define DebugInt3
    #define DEBUG_ASSERT(expr) assert(expr)
#endif

    //usage
    void doStuff()
    {
        //here the debugger will stop if the function is called 
        //and your coworker will read your message
        DEBUG_ASSERT(0); //TODO: will be implemented on the next week; 
                         //postcondition number 2 of the doStuff is not satisfied;
                         //proceed with care /Johny J.
    }

优点:

  1. 代码可以编译和运行。
  2. 只有当开发人员在测试期间遇到您的代码时,他才会收到有关未实现内容的消息,因此他不会被不必要的信息淹没。
  3. 该消息指向相关代码(而不是异常捕获块或其他内容)。调用堆栈可用,因此可以追踪调用未完成代码的位置。
  4. 开发人员在收到消息后可以继续进行测试运行而无需重新启动程序。

缺点:

  1. 要禁用消息,必须注释掉一行代码。这种更改可能会悄悄地出现在提交中。

P.S. 初始DEBUG_ASSERT实现的功劳归于我的同事E.G.


__asm__("int $0x3;")替换__emit__(0x90CC)会不会更好呢? - tauran
@tauran:在类模板中不允许使用汇编语言(至少在我的IDE中是这样),因此无法在任何地方使用它。 - Alsk
这个交叉编译器有多强大? - André Fratelli

0

你可以使用纯虚函数(= 0;)来继承类,或者更常见的做法是声明它们但不定义。不能调用没有定义的函数。


纯虚函数需要在其中一个派生类中实现。 - jamesdlin
重点不在于这样做。这样,如果他们试图打电话,它将失败。 - Puppy
代码无法编译,导致已经实现的类其余部分无用。 - rubenvb
目标是确保特定的方法不能被调用,而不是完全破坏现有的派生类(或基类本身的消费者,这些消费者将突然变得不可实例化)。如果派生类提供了一个存根实现来修复构建问题,那么当基类提供实际的方法实现时,派生类仍将愉快地使用错误的版本。很好。使用纯虚方法是没有意义的。(您关于简单地不实现这些方法的第二个建议是可以的。) - jamesdlin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接