像C#这样编写代码是否合法?

3

Example:

H

class MyClass {
    int x,y,z;
public:
    MyClass(int,int,int);
    void X();
    void Y();
    void Z();
};

C++

class MyClass {
    int x,y,z;
public:
    MyClass(int x,int y,int z) {
        this->x=x;
        this->y=y;
        this->z=z;
    }
    void X() {
        printf("x = %d;\n",x);
    }
    void Y() {
        printf("y = %d;\n",y);
    }
    void Z() {
        printf("z = %d;\n",z);
    }
};

让它看起来像C#。 不要包含头文件,在CPP文件中重新声明类但带有方法体。 当文件包括头文件时,它会从CPP获取extern字段、方法等。

这合法吗?我不能预测其中的问题。存在问题吗?


1
如果编译并运行成功,那么它就是合法的。如果不能成功,那么就不合法。简单明了。 - musefan
11
很多无效的C++代码可以干净地编译。 - Mat
1
你为什么要使用 this->x 而不是像 x(x) 这样初始化? - tadman
2
@musefan:什么是非法代码?drugs.sell(plenty) - Mat
1
@Mat:你应该小心在公共场所(如SO)发布那种代码... 十分钟后在后门见我,并带上你最喜欢的文本编辑器。 - musefan
显示剩余13条评论
3个回答

11

这属于单一定义规则的范畴。特别地,针对同一程序中多个翻译单元内相同类的多个定义,要求如下:

[...] - D 的每个定义必须由相同的标记序列组成 [...]

(3.2 单一定义规则 [basic.def.odr] 第5段)

因此,即使您“修复”第一个版本以声明成员函数为 inline 以匹配第二个版本(在其中提供成员的定义会隐式声明它们为 inline),您仍将违反此规则:函数体是出现在一个版本而不出现在另一个版本中的额外标记。


只要源文件中未包含头文件,就不存在正式问题,因为编译器会完全忽略头文件。 - Qnan
2
@Qnan 或许你在我澄清之前已经读过我的回答了,这里的规则是关于不同翻译单元中的多个定义。ODR 在翻译单元级别和程序级别分别起作用。 - Luc Danton
我不是在争论那个,只是想指出这个问题根本没有意义。它之所以能编译,仅仅是因为头文件没有被包含在任何源文件中。 - Qnan
2
@Qnan 你可以在一个TU中定义一个类,然后将该定义复制并粘贴到另一个TU中,如果适当地处理,你将拥有一个正确的程序。请记住,#include机制是以文本包含为基础定义的--规则必须根据我的说法进行调整才能使其工作。而它们已经做到了,并且确实起作用。从那里开始,只需要稍微思考一下,就会想知道如果这两个定义在某些方面不同会发生什么。这就是那位好奇心的人的问题的答案。 - Luc Danton
非常好,我现在明白你的意思了。你认为实际执行这个有什么优势吗? - Qnan

5

这违反了一定义规则部分的3.2/5条规定。

一个类类型(第9节)可以有多个定义,...[其他类型和条件不重要]

只要这些定义满足以下要求。 给定一个名为D的实体,在多个翻译单元中定义, 那么

-- D的每个定义都应该由相同的标记序列组成;

如果在任何其他链接的翻译单元中包含头文件,这显然禁止了这种机制。

如果您想编写C#,请直接使用C#编写。如果您编写符合惯用法的C++而不是方言,那么您的未来维护者将不胜感激。


这不是真的。类定义可以重复,只是不能在同一个TU中重复。否则,你永远无法拥有使用相同类的两个TUs。 - Scrubbins

-1

一个主要的问题将是循环引用:如果类 A 的代码包含类 B 的实例,而类 B 又使用了类 A,编译将会失败。

将类分离为声明(.h)和定义(.cpp)可以解决这个问题。

但是:如果你仍然想把类的定义放在头文件中,你可以通过将类变成模板来实现,从而推迟类型解析。但这会增加编译时间的代价!


3
这是另一个问题的正确答案,但不是这个问题的答案。 - Xeo
OP建议将类在头文件中声明,并在.cpp文件中进行定义。 - Qnan
他这样做了吗?抱歉,我误解了他的问题。但我不会称其为“C#方式”…… - Daniel Gehriger

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