3

I am very new to C++. I am comfortable with Java and Python and I am trying to do a quickstart into C++.

I am trying to figure out how to declare/define a non-member function that takes an argument to a class object by-reference. I am unable to compile my code. I have tried to replicate the problem in the set of three files below.

I am using eclipse (Luna) as an IDE which in turn is using g++ on Ubuntu 14.04. In this set I get a cryptic compile error in the declaration of the non-member function in MyTest.h, which goes like "explicit qualification in the declaration of 'void mytest::printInt(ostream&, MyTest&)"

In my real world example I am getting a very similar error in the definition (not declaration) of the analogue of this function.

Initially I thought it has to do with me preventing the compiler from creating a default constructor and the "MyTest& m" somehow needing a default constructor (though that totally didn't make any sense to me). But declaring and defining a default constructor doesn't change the problem.

What am I doing wrong? What is the right way to define a non-member function that takes class objects as arguments by-reference)? What are some larger lessons to be had from this?

In file Mytest.h:

#ifndef MYTEST_H_
#define MYTEST_H_

#include<iostream>

namespace mytest {

using std::ostream;

class MyTest {
public:
    MyTest(int a) : a(a) {}
    int getA() { return a; }
private:
    int a;
};

void mytest::printInt(ostream& os, mytest::MyTest& m);

} /* namespace mytest */

#endif /* MYTEST_H_ */

In file MyTest.cpp

#include "MyTest.h"

namespace mytest {

void mytest::printInt(ostream& os, MyTest& m){
    os << m.getA();
}

} /* namespace mytest */

And finally a file to run them, Test.cpp:

#include "MyTest.h"

using mytest::MyTest;
using std::cout;
using std::endl;

int main(void) {
    MyTest a = MyTest(1);
    mytest::printInt(cout, a);
}
Galik
  • 47,303
  • 4
  • 80
  • 117
TimBeaver
  • 213
  • 1
  • 9
  • 1
    `I am comfortable with Java ... trying to do a quickstart into C++.` Just don´t, it slows you down. – deviantfan Jun 16 '15 at 21:24
  • 1
    appreciate the advice deviantfan - any comments about what went wrong in my code above? – TimBeaver Jun 16 '15 at 21:26
  • `C++` is very different from `Java! despite similar syntax. Recommended reading: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Galik Jun 16 '15 at 21:34
  • Understand that fully Galik. Reading through "Accelerated C++" and "C++ Primer" with a focus on classes, details of construction and destruction, details of memory management, inheritance and polymorphism. – TimBeaver Jun 16 '15 at 21:40

4 Answers4

6

In the declaration and definition of printInt function remove "mytest::" from the function name. It is already in the mytest namespace because of the namespace block.

tsandy
  • 911
  • 4
  • 10
3

In MyTest.h and MyTest.cpp replace

void mytest::printInt(ostream& os, mytest::MyTest& m)

with

void printInt(ostream& os, mytest::MyTest& m)

mytest:: is not needed because your declaration and definition already are inside a namespace block.

On a side note, I recommend using Clang for (sometimes) a bit less cryptic error messages. Clang says about this line:

./MyTest.h:18:14: error: out-of-line declaration of 'printInt' does not match any declaration in namespace 'mytest'
void mytest::printInt(ostream& os, mytest::MyTest& m);
             ^~~~~~~~

vs GCC's

MyTest.h:18:53: error: explicit qualification in declaration of ‘void mytest::printInt(std::ostream&, mytest::MyTest&)’
 void mytest::printInt(ostream& os, mytest::MyTest& m);
Lukas W
  • 305
  • 1
  • 9
1

You should not add the namespace qualifier from within the namespace:

namespace mytest {

using std::ostream;

class MyTest {
public:
    MyTest(int a) : a(a) {}
    int getA() { return a; }
private:
    int a;
};

// no namespace qualifier here
void printInt(ostream& os, MyTest& m);

} /* namespace mytest */


namespace mytest {

// no namespace qualifier here
void printInt(ostream& os, MyTest& m){
    os << m.getA();
}

Then:

using mytest::MyTest;
using std::cout;
using std::endl;

int main(void) {
    MyTest a = MyTest(1);
    mytest::printInt(cout, a); // now use the namespace qualifier
}
Galik
  • 47,303
  • 4
  • 80
  • 117
  • I tried this and now I am getting a compile error in Test.cpp. – TimBeaver Jun 16 '15 at 21:31
  • sorry I don't know why that went incomplete, typing a complete reply below. – TimBeaver Jun 16 '15 at 21:31
  • I edited as such and now the printIt invocation in Test.cpp (which in turn looks like "printint(cout, a)" (without any namespace qualifiers). The error is like this: "undefined reference to mytest::printIt(std::ostream&, mytest::Mytest&)". Note that I have added a "using mytest::printit" to the top of teh file. – TimBeaver Jun 16 '15 at 21:32
  • I also tried the version you indicated, and I get the same error message as above: "undefined reference to mytest::printIt(..." etc. – TimBeaver Jun 16 '15 at 21:35
  • 1
    @TimBeaver It sounds like your `MyTest.o` is not getting linked in for some reason. – Galik Jun 16 '15 at 21:37
  • This is really weird. The output of my make is: $ make g++ -o Test Test.o Test.o: In function `main': /home/noname/cpp/Test//Test.cpp:17: undefined reference to `mytest::printInt(std::ostream&, mytest::MyTest&)' collect2: error: ld returned 1 exit status make: *** [Test] Error 1 – TimBeaver Jun 16 '15 at 21:45
  • So it looks like Test.o is being passed to the linker. And I do see Test.o. Also, just to avoid any confusion, my Test.cpp file now looks like so: #include "MyTest.h" using mytest::MyTest; using std::cout; using std::endl; int main(void) { MyTest a = MyTest(1); mytest::printInt(cout, a); } – TimBeaver Jun 16 '15 at 21:46
  • Ah I see what you are saying. There is no Mytest.o – TimBeaver Jun 16 '15 at 21:47
  • 1
    @TimBeaver Looks like your build is wrong, it should be compiling `MyTest.cpp` to produce `MyTest.o` and adding that to be linked in when it links `Test.o` – Galik Jun 16 '15 at 21:49
  • Correct, Galik. Thanks, that's what it was. I was counting on the IDE to build the Makefile. My mistake. – TimBeaver Jun 16 '15 at 21:52
0

Yoohoo, I got it. My Makefile was bad, as pointed by Galik. Adding MyTest.o to the list of OBJS fixed it.

CXXFLAGS = -O2 -g -Wall -fmessage-length=0

OBJS =  Test.o MyTest.o

LIBS =

TARGET = Test

$(TARGET): $(OBJS)
 $(CXX) -o $(TARGET) $(OBJS) $(LIBS)

all: $(TARGET)

clean:
 rm -f $(OBJS) $(TARGET)
TimBeaver
  • 213
  • 1
  • 9