开发者

same class, different size...?

See the code, then you would understand what I'm confused.

Test.h

class Test {
public:
#ifndef HIDE_VARIABLE
    int m_Test[10];
#endif
};

Aho.h

class Test;

int GetSizeA();
Test* GetNewTestA();

Aho.cpp

//#define HIDE_VARIABLE
#include "Test.h"
#include "Aho.h"

int GetSizeA() { return sizeof(Test); }
Test* GetNewTestA() { return new Test(); }

Bho.h

class Test;

int GetSizeB();
Test* GetNewTestB();

Bho.cpp

#define HIDE_VARIABLE   // important!
#include "Test.h"
#include "Bho.h"

int GetSizeB() { return sizeof(Test); }
Test* GetNewTestB() { return new Test(); }

TestPrj.cpp

#include "Aho.h"
#include "Bho.h"
#include "Test.h"

int _tmain(int argc, _TCHAR* argv[]) {
    int a = GetSizeA();
    int b = GetSizeB();

    Test* pA = GetNewTestA();
    Test* pB = GetNewTestB();

    pA->m_Test[0] = 1;
    pB->m_Test[0] = 1;

    // output : 40     1
    std::cout << a << '\t' << b << std:开发者_如何学JAVA:endl;

    char temp;
    std::cin >> temp;

    return 0;
}

Aho.cpp does not #define HIDE_VARIABLE, so GetSizeA() returns 40, but Bho.cpp does #define HIDE_VARIABLE, so GetSizeB() returns 1. But, Test* pA and Test* pB both have member variable m_Test[].

If the size of class Test from Bho.cpp is 1, then pB is weird, isn't it?

I don't understand what's going on, please let me know. Thanks, in advance.

Environment: Microsoft Visual Studio 2005 SP1 (or SP2?)


You violated the requirements of One Definition Rule (ODR). The behavior of your program is undefined. That's the only thing that's going on here.

According to ODR, classes with external linkage have to be defined identically in all translation units.


Your code exhibits undefined behavior. You are violating the one definition rule (class Test is defined differently in two places). Therefore the compiler is allowed to do whatever it wants, including "weird" behavior.


In addition to ODR.

Most of the grief is caused by including the headers only in the cpp files, allowing you to change the definition between the compilation units.

But, Test* pA and Test* pB both have member variable m_Test[].

No, pB doesn't have m_Test[] however the TestPrj compilation unit doesn't know that and is applying the wrong structure of the class so it will compile. Unless you compile in debug with capturing of memory overrun you would most times not see a problem.
pB->m_Test[9] = 1; would cause writing to memory not assigned by pB but may or may not be a valid space for you to write.


Like many people told here, you've violated the so-called One Definition Rule (ODR).

It's important to realize how C/C++ programs are assembled. That is, the translation units (cpp files) are compiled separately, without any connection to each other. Next linker assembles the executable according to the symbols and the code pieces generated by the compiler. It doesn't have any high-level type information, hence it's unable (and should not) to detect the problem.

So that you've actually cheated the compiler, beaten yourself, shoot your foot, whatever you like.

One point that I'd like to mention is that actually ODR rule is violated very frequently due to subtle changes in the various include header files and miscellaneous defines, but usually there's no problem and people don't even realize this.

For instance a structure may have a member of LPCTSTR type, which is a pointer to either char or wchar_t, depending on the defines, includes and etc. But this type of violation is "almost ok". As long as you don't actually use this member in differently compiled translation units there's no problem.

There're also many other common examples. Some arise from the in-class implemented member functions (inlined), which actually compile into different code within different translation units (due to different compiler options for different translation units for instance).

However this is usually ok. In your case however the memory layout of the structure has changed. And here we have a real problem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜