C++标准,是否允许两个互不可见的类重名?该怎么解决

C++标准,是否允许两个互不可见的类重名?
以下是一个测试程序,编译器是 VS2010

test1.cpp:


class Cs
{
public:
    int test()
    {
        return 1;
    }
    int test1()
    {
        return 10;
    }
};

int test1()
{
    return Cs().test() + Cs().test1();
}


test2.cpp:


class Cs
{
public:
    int test()
    {
        return 2;
    }
    int test2()
    {
        return 20;
    }
};

int test2()
{
    return Cs().test() + Cs().test2();
}


main.cpp:


#include <stdio.h>
#include <stdlib.h>

int test1();
int test2();

int main()
{
    printf("%d %d\n", test1(), test2());
    system("pause");
    return 0;
}


输出结果竟然是的:11 21


疑问:

1、同一个编译模块中,C++标准是否允许两个类重名,或者这个根本不是标准的一部分?
2、出现这样的情况是不是MS链接器的BUG?
3、如果C++标准允许类重名,链接器也没有问题,那这算不算是C++标准的一个缺陷?

------解决思路----------------------
实际上,C++标准或者说大概所有的语言标准,都只规定了“如果你这么写,那么我可以保证得到什么结果”
正确的行为是有限的,错误的行为是无限的,C++标准可以明确规定其中一些行为是不允许的,但更多的错误行为不可能被全部包罗进来,甚至有些行为标准委员会可能都想不到。这类错误行为,我们称为“未定义”
未定义行为会得到什么样的结果,取决于具体处理这段代码的编译器,也许你用MS的编译器会得到某种结果或者报错,用G++又会得到另一种结果或者报错,诸如此类

通过编译器的编译不代表就是正确代码,C++标准没规定不可以写不代表就可以写

如果上面这些话楼主都不爱听,觉得是废话,那就说点也许有用的
别为难编译器,你敢为难编译器,编译器就敢玩死你
编译器只负责把你的代码转换成机器命令,如果你们之间发生了矛盾,到底是谁倒霉?我想比尔盖茨不会在意你的老板对你编写的程序发火拍桌子甚至找人事部。
只写你确定你知道会得到什么结果的代码

好吧,我承认我完全不熟悉C++标准原文
楼主提出的这类问题,我向来是按照上面的原则回避掉的
等高人回答吧,记得这里有几个标准党,是我等小白的福音
------解决思路----------------------
引用:
为什么不是 11 22 ?

大概,编译器对Cs().test()、Cs().test1()、Cs().test2()三个函数分别进行了编译
而Cs().test()在test1.cpp里被编译过一次后,test2.cpp里的那个就被无视了
------解决思路----------------------
test1.cpp和test2.cpp都是编译单元,并且其中的Cs互不可见,并不会对编译产生影响。所以代码产生结果的问题应该是在链接环节上,受链接器内部工作原则和细节决定,例如test1.obj和test2.obj在链接是会不会发生合并,或者根据链接顺序具有优先级?不得而知。
------解决思路----------------------
推测是链接顺序的问题。
如果
g++ -o demo main.cpp test1.cpp test2.cpp
输出就是11, 21, Cs.test()首先在test1.cpp里找到所以Cs.test()返回1

如果
g++ -o demo main.cpp test2.cpp test1.cpp
输出就是12, 22, Cs.test()首先在test2.cpp里找到所以Cs.test()返回2

------解决思路----------------------
第一,就这么几行代码,怎么可能出现重名问题而不能发现?
第二,如果代码量很巨大,那么在使用上就不可能像这几行代码这样这么随意,如果你把类声明都include进来,编译时就发现问题了。
第三,c++提供了命名空间。

最后,我们不要把精力花在毫无意义的假设和对这毫无意义的假设进行求证之上。
------解决思路----------------------
我给楼主提供一条思路。因为如果以楼主这样在test1.cpp与test2.cpp2个CPP文件里面定义不加任何修饰的text()函数,会使test1.cpp里面的text()函数在链接时覆盖掉test2.cpp里面的text(),于是就得出楼主的结果。你可以声明text()为虚函数(virtual text())这样有可能会得到楼主想要的结果。
//都声明为虚函数  结果是12 22.
//2个text函数只声明一个为虚函数 结果为 11 22.我想这个应该是楼主想要的答案。这样两个text函数就互不干扰了。
//都不声明为虚函数 结果就是楼主的结果。

------解决思路----------------------
这样的问题我觉得在事先就该规划好,防止隐患吧
------解决思路----------------------
在类声明中写实现的话则 函数就是inline的函数 ,而inline函数也会存在当前编译单元符号表中。

编译器会保证 同样函数签名的inline函数不会链接冲突。

如果有两个不一样实现的inline函数,那么编译器就就自己决定用哪个实现,所以inline函数都会写在头文件中保证在每个编译单元中实现一致。

------解决思路----------------------
引用:
1、同一个编译模块中,C++标准是否允许两个类重名,或者这个根本不是标准的一部分?
2、出现这样的情况是不是MS链接器的BUG?
3、如果C++标准允许类重名,链接器也没有问题,那这算不算是C++标准的一个缺陷?

1.不允许。不过主楼的程序涉及三个不同的 translation units,所以和同一个 translation unit 是否允许重名没有关系。标准相关的定义叫 one definition rule (ODR),c++11 3.2/5
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then 
— each definition of D shall consist of the same sequence of tokens; and ...

主楼程序中的 test 函数在 test1.cpp 和 test2.cpp 中的 sequence of tokens 是不一样的,因为一个是 return 1; 另一个是 return 2;
因此,主楼的程序违背了 ODR 原则,属于 C++ 经典的 undefined behavior.

2.这里不存在 bug 可言。因为所谓的 bug 是说程序的行为与正确的行为不一致,但是 c++ 标准说主楼程序的行为是 undefined,因此没有所谓正确的行为,因此也没有 bug 可言。

3.显然不是 c++ 的缺陷。c++ 对此有清晰的定义,叫做 undefined behavior。简而言之,就是不要写这样的程序,属于标准认证的自找麻烦的程序。
------解决思路----------------------
编译器在执行某方法时会跳到方法内部,然后再return到原方法中,
由于是非static 方法,所以是在用到时才编译的方法,
你的类名,方法名相同,编译器会认为是同样一个东西, 所以不再重复编译同名方法,
其实你第二个CPP中,调用了第一个类里面的test()方法。
调试结果确实是这样。。。
------解决思路----------------------
这涉及到编译的时候common块问题,你可以搜索一下。
------解决思路----------------------
引用:
编译器在执行某方法时会跳到方法内部,然后再return到原方法中,
由于是非static 方法,所以是在用到时才编译的方法,
你的类名,方法名相同,编译器会认为是同样一个东西, 所以不再重复编译同名方法,
其实你第二个CPP中,调用了第一个类里面的test()方法。
调试结果确实是这样。。。

这是局限于 vs 的片面结论,比如我用 g++-4.7.0 编译,输出结果就是 11 22。标准说的是 undefined behavior,意思就是编译器自己看着办,因此在这个程序上 vs 和 g++ 可以说都是正确的。只不过这种程序基本是无用的,因为其行为没有确定性。