1

I'm learning about constructors in C++, but the MSVS compiler is behaving strangely, and I don't understand why. The success of the compiler appears to be dependent on recent attempts at compilation. My expectation is that if my code successfully compiles once, it should always successfully compile, and if it gives an error, it should always give an error. With my code here, that is not the case. I'm using the debugger in the free MSVS 2019 IDE on Windows 10.

I have 3 files that form my project, and 3 different versions of the project I will call A, B, and C.

Version A is the code as presented in the first three displays below. I think version A should compile and run as I expect. Any actual errors in version A are probably secondary to this question. The code should define a class, create an instance of the class (running the constructor), call a method of the class, and finally call the destructor for that object when the program terminates.

The following code is in Cat.h.

#pragma once
#include <iostream>

class Cat {

private:
    bool happy;

public:
    Cat();
    ~Cat();
    void meow();
};

The following is in file Cat.cpp.

#include <iostream>
#include "Cat.h"

Cat::Cat() {
    std::cout << "Creating Cat" << std::endl;
    happy = false;
};

Cat::~Cat() {
    std::cout << "Deleting Cat..." << std::endl;
};

void Cat::meow() {
    if (happy) {
        std::cout << "Meow" << std::endl;
    }
    else
    {
        std::cout << "SSSSSsssss" << std::endl;
    }
    return;
};

The following is my main file.

#include "Cat.h"

int main() {
    Cat cat;
    cat.meow();
}

Version B is identical to version A, except with the one change that happy is declared in the constructor for Cat, making happy a local variable of the constructor.

Cat::Cat() {
    std::cout << "Creating Cat" << std::endl;
    bool happy = false;
}

Version C is identical to version A, except with the obvious error that the semicolon is removed after the class declaration in Cat.h.

    Cat();
    ~Cat();
    void meow();
}

Now for the weird behavior.

If I first attempt to compile version A, I get the following errors:

1>Debug\Cat.obj : warning LNK4042: object specified more than once; extras ignored
1>Source.obj : error LNK2019: unresolved external symbol "public: __thiscall Cat::Cat(void)" (??0Cat@@QAE@XZ) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "public: __thiscall Cat::~Cat(void)" (??1Cat@@QAE@XZ) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "public: void __thiscall Cat::meow(void)" (?meow@Cat@@QAEXXZ) referenced in function _main

If I now change version A to version B and compile, I get no errors, but the I'm not initializing happy in the constructor of cat. If I then change version B back to version A, the code compiles and runs as I expect.

Now version A compiles and runs, even though it is the same code that was giving me an error before.

If I now change version A to version C and compile, I get the obvious error:

 1>Cat.cpp
 error C2533: 'Cat::{ctor}': constructors not allowed a return type
 1>Cat.h 
 fatal error C1004: unexpected end-of-file found

If I now change this version C to version A and compile, I get the same error that followed the initial compilation of version A. Reverting to version B and back fixes that problem.

fm2725789
  • 11
  • 1
  • Maybe its related to this: https://stackoverflow.com/questions/3695174/visual-studio-2010s-strange-warning-lnk4042 – drescherjm Apr 17 '19 at 04:56
  • What do you mean by "change version A to version B"? Are you editing one source file, renaming sources, adding and removing sources from the project, or something else? – 1201ProgramAlarm Apr 17 '19 at 04:57
  • @1201ProgramAlarm After writing version X, I right clicked the project name and pressed "Build." I then right clicked the project name and selected "Start new instance" under Debug in the context menu to run version X. To switch to version Y, I immediately changed the code for version X within the IDE without closing it. I right clicked the project name and pressed "Build" and then "Start new instance." – fm2725789 Apr 17 '19 at 05:10
  • Concerning your last comment: If you compile and run a project in VS2013 (and surely as well in VS2019): While the executable is running, you may compile sources but you cannot link. Linking tries to overwrite the `.exe` file but that's prohibited while this `.exe` file is still running. (The same applies to projects building `.dll` files btw.) (I'm still not sure about what you described in your question. So, this is just a hint, in case.) – Scheff's Cat Apr 17 '19 at 05:40
  • @drescherjm I renamed Cat.h to Cat2.h and corrected the corresponding #include's in Cat.cpp and Source.cpp. It seems that the convention is that .h and .cpp files of a class have the same file name. Am I to avoid that convention when using the Visual Studios compiler? That fixes the issue, but doesn't really answer my question. I don't believe answers to that question offer solutions and explanations at the level I am at. I need a more direct answer to the question "Why does C++ code sometimes compile and sometimes give a compilation error depending on previous compilations?" – fm2725789 Apr 17 '19 at 05:50
  • @Scheff If I understand your comment correctly, you think I might have built the code while it was still executing. I did not do that. I closed the MSVS console before building version Y. – fm2725789 Apr 17 '19 at 06:19
  • One "solution" that does not answer my question: If I create a new class by right clicking "Source Files" and selecting "Add > Class" in the context menu, I do not experience the problem described in this post. If I manually create the .h and .cpp files for my class, I do experience the problem described in this post. – fm2725789 Apr 17 '19 at 06:21
  • It's the usual convention to name .h and .cpp files with equal name - that's usual in VS as well. I usually create .cpp and .h files manually (e.g. in Explorer with New Text File) and add them as sources. You don't force VS to compile your .h files? .h files are added to a separate folder (Header Files) for convenience but not for compiling. Every C/C++ compiler "automatically" loads them for every resp. `#include` which is found in source code (.cpp files). – Scheff's Cat Apr 17 '19 at 06:33
  • To be clear: You could force VS (and any other C++ compiler) to compile a .h file directly. (It then becomes a [translation unit](https://en.wikipedia.org/wiki/Translation_unit_(programming)) on its own.) But now, you have two problems. Beside of that this is not _the_ convention, the .cpp file with same name will yield the same object file (as the source suffix is simply replaced by `.obj`). That's not for what header files are intended for. .cpp -> a translation unit -> compiled. .h -> a header -> `#include`d. – Scheff's Cat Apr 17 '19 at 06:36
  • Try using "Rebuild" instead of "Build" and see if that changes anything – rcs Apr 17 '19 at 08:00

0 Answers0