用Java方式定义C++类

Xiè*_*léi 0 c++ programming-languages

这可能不是一个真正的问题,请关闭它,如果它不合适.

在C++中,你不能混用在一个源文件的标题和实施,例如,类将被两次,如果它是由包括定义a.ccb.cc:

// foo.h
#pragma once
class Foo {
    void bar() { ... }
};

// a.cc
#include "foo.h"
class A {};

// b.cc
#include "foo.h"
class B {};

// Link all
$ gcc -c -o a.o a.cc
$ gcc -c -o b.o b.cc
$ gcc -o main main.cc foo.o a.o b.o
Run Code Online (Sandbox Code Playgroud)

然后,它是三个目标文件中的模糊Foo :: bar()!

相反,我们必须将实现分成另一个文件:

// foo.h
#pragma once
class Foo {
    void bar(); 
};

// foo.cc
# include "foo.h"
void Foo::bar() { ... }
Run Code Online (Sandbox Code Playgroud)

虽然可能不是一个大问题,因为通常foo :: bar()的二进制文件a.ob.o它们是相同的.但至少有一些冗余的声明,不是吗?还有一些由此多余造成的混淆:

  1. 在哪里给出可选参数的默认值?

    class Foo {
        void bar(int x = 100); 
    };
    
    Run Code Online (Sandbox Code Playgroud)

    要么,

    void Foo::bar(int x = 100) { ... }
    
    Run Code Online (Sandbox Code Playgroud)

    或两者?

  2. 在内联和内联之间移动......?

    如果要将非内联函数切换为内联函数,则应将代码从中foo.cc移至foo.h,并添加inline关键字前缀.也许两秒钟之后,你会对你所做的事感到遗憾,然后,你将内联的内容移foo.h回到foo.ccinline再次删除关键字.

    但如果声明和定义是一起的话,你不需要这样做.

还有更多这种轻微的头痛.

这个想法是,如果你只是随着声明一起编写一个函数的定义,那么编译器就无法推断函数的原型.

例如,通过使用单个source.cc,并仅导入类型信息,例如,

#include_typedef "source.cc"
Run Code Online (Sandbox Code Playgroud)

事情会变得更简单.编译器很容易忽略变量分配和函数定义,只需在构造AST之前在解析器时进行过滤,不是吗?

我习惯于在单独的源/头文件中编程,我当然能够进行分离.你可以争论编程风格,但是,这会降低问题是什么是将逻辑表示为更好的编程风格的正确方法.我不认为Java是源/头分离上下文中更好的编程风格.但Java提供了正确的方法.

你介意把标题与类分开吗?如果可能的话,你会如何将它们混合成一个?是否有任何C++前端可以将声明和定义分离为混合源中的单独文件?或者我怎么写这样的?(我的意思是海湾合作委员会.)

编辑

无论如何我不是在抨击C++,如果你从这个问题中得到错误的信息,我很抱歉.

由于C++是一种多范式语言,您可以通过使用魔术宏来了解MFC如何设置消息绑定,以及boost库如何使用模板实现所有内容.当分离进入问题域时,(感谢ONeal指出该域属于包装系统),人们可以尝试找出解决方法.对我来说,有很多种编程风格,因为我花了很多时间编写C++,所以任何小的方便都可以很方便地累积.写入实现以及声明是方便的.我想如果我不需要将它们分开,我可以将源线减少至少10%.您可能会问,如果方便是如此重要,为什么不使用Java呢?显然C++与Java不同,它们不可互换.

内联函数可能解决问题,但它根本改变了语义.

Ich*_*hyo 5

有了这个问题,你就会提出通常的C++编译系统的根本缺点.但是,让这种情况有所帮助,你的第一个例子似乎就会出现问题.事实上,这样一种风格,你把你所有的课程完全内联,完美地运作.当您开始更深入地使用模板时,它甚至是使事情有效的唯一方法.例如,boost库大多只是标题,即使是涉及最多的技术细节都是内联编写的,因为它不会起作用.

我的猜测是你错过了所谓的标题守卫 - 从而获得了重新定义警告.

// foo.h --------

#ifndef FOO_H
#define FOO_H

class Foo {
    void bar() { ... }
};

#endif // FOO_H
Run Code Online (Sandbox Code Playgroud)

这应该工作正常

  • @ J-16:现代还是不,标题守卫是标准的,`#pragma once`不是 (2认同)