strange behavior with friend functions -- scope "globalized" when object pointer passed? - c++

Let's say I have a header file a.h and a source file a.cpp. When I try to compile this and call what() from a different file (e.g. main.cpp) which includes a.h:
a.h:
class A {
friend void what();
public:
int index;
};
a.cpp:
#include "a.h"
#include <iostream>
void what() {
std::cout << "what" << std::endl;
}
It fails, as expected (error: 'what' was not declared in this scope). However, when I do the same thing with this:
a.h:
class A {
friend void what(A *thing);
public:
int index;
};
a.cpp:
#include "a.h"
#include <iostream>
void what(A *thing) {
std::cout << thing->index << std::endl;
}
It compiles and runs just fine on g++ 4.4.1 (assuming "index" has been initialized, of course). I don't know much about C++, but I would assume that, by passing the object pointer to the function, the function somehow became available to the global scope (i.e. gets "promoted" in order to be able to "see" an object which previously existed on the same scope as it). I haven't tried this with other kinds of functions yet, but, when using g++ and friend functions, I get this behavior. Is this supposed to happen in C++?
Thanks and sorry if this is a noobish question, my friend Google was failing me.

I compiled your code with g++ 4.5.1 and no error was reported.

I think you have forgotten ; at the end of your class declaration.
Following code works perfectly fine for me (gcc 4.4.5)
a.h
class A {
friend void what();
private:
int index;
};
a.cpp
#include <iostream>
#include "a.h"
using namespace std;
void what()
{
cout << "what" << endl;
}
int main()
{
what();
return 0;
}
UPDATE
You should declare what function in the a.h header file before A class declaration.

Related

Member function definition outside the class

Firstly, I am giving the codes. Then I am explaining the problem I am facing.
main.cpp
#include <iostream>
#include "acc.h"
using namespace std;
class mem;
int main()
{
show();
return 0;
}
acc.h
#ifndef ACC_H
#define ACC_H
#include "acc.cpp"
void show();
class mem{
int a;
public:
void showa();
void seta(int A);
};
#endif
acc.cpp
#include <iostream>
using namespace std;
void mem::showa(){cout<<a<<endl;}
void mem::seta(int A){a = A;}
void show()
{
mem m;
m.seta(22);
string ss;
cin>>ss;
cout<<"MY name is "<<ss<<" ";
m.showa();
}
"mem" class I declared in "acc.h" file already and added that "acc.h" into acc.cpp file also. But when I am calling that class from a function. It can't response. Showing "a" and "mem" not declared. How can I perfectly link that class definition and member functions of that class so that calling member functions of that class from another function can't create any problem?
If you remove the #include "acc.cpp" from the acc.h file it should compile without any errors. I tried and it compiles for me. I am using Visual Studio 2010 for the same.
Other than this, few more comments:
You can use #pragma once in you header file instead of #ifndef/#define macros. The former is more cleaner.
You dont need to forward declare class mem before main() as you are already including acc.h.
the show() can be moved to where main() is defined making the acc.h/acc.cppfiles dedicated for the mem class.
A header file should always be named after the class it is holding i.e. mem.h/mem.cpp in your case. This informs which file contains which class even without opening the file.

Nonstatic Member Reference with "std::cout" in Header

I'm sort of new to C++, and I've been making my way through a bit in my own project. I ran into an error with this header and .cpp file
// main.cpp
#include <iostream>
#include "Header.h"
int main() {
MyClass::TestFunction(); //'MyClass::TestFunction': illegal call of non-static member function
}
// header.h
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
class MyClass {
public:
void TestFunction() {
std::cout << "Hello World\n"; //Where I beleive the issue is
}
};
#endif
Now I think the issue comes from std::cout not being static and the declaration in main.cpp needs it to be static, but I'm not sure how to make it static so that main.cpp works correctly. If anyone could give me a tip as to how I can make things like this work later on down the road, that would be awesome :)
the issue comes from std::cout not being static and the declaration in main.cpp needs it to be static
You either have to make your function static OR to intanciate an object of your class and hen call its function :
main.cpp
int main() {
MyClass pony;
pony.TestFunction();
}
OR
header.h
class MyClass {
public:
static void TestFunction() {
std::cout << "Hello World\n";
}
};
whenever a member function is written inside a class, it can be called only using object. You have to create a object in main function.
// main.cpp
#include <iostream>
#include "header.h"
int main() {
MyClass myObject;
myObject.TestFunction(); //'MyClass::TestFunction': illegal call of non-static member function }
OR
If you dont want to use object, then make the member function as static.
// header.h
#ifndef HEADER_H
#define HEADER_H
#include <iostream>
class MyClass { public:
void static TestFunction() {
std::cout << "Hello World\n"; //Where I beleive the issue is
} };
#endif

Class declarations in header files

Ive been using c++ for some months now but Ive come across an error when I use header and source code files. I create a source code file
that contains a class gun(example not actual program):
class gun
{
private:
int stuff;
public:
void doStuff();
};
void Gun::doStuff()
{
cout << stuff << endl;
}
and then i created a header file and declared the class like this:
class gun;
then in my main source file i do this:
int main()
{
gun *mygun = new gun;
mygun->doStuff();
return 0;
}
however when i try to execute it i get the error:
invalid use of incomplete type 'class gun' and i think the problem is how i declared it in the header, did i do it wrong? how was i meant to do it? thanks.
Thanks Everyone that helped! I understand now, i thought that only the forward declaration
went into the header file, thanks for all your answers!
You seem to be going about seperating the implementation and header file the wrong way. Forward declarations should not go in the header file. The entire declaration should! This is how your code should be structured
Gun.hpp
#pragma once
class Gun
{
private:
int stuff;
public:
void doStuff();
};
Gun.cpp
#include "Gun.hpp"
#include <iostream>
using std::cout;
using std::endl;
void Gun::doStuff()
{
cout << stuff << endl;
}
main.cpp
int main()
{
Gun *mygun = new Gun;
mygun->doStuff();
delete mygun; // <-- remember this!
return 0;
}
the separation of header and implementation is crucial in C++ and other languages! You should only declare the class in the header along with its full interface (as above) and include all implementation details in the .cpp file (as above :)
The entire declaration of the gun class needs to be in the header file. What you declared in the header file is a forward declaration, which is not enough by itself to create an instance of the class. Forward declarations are useful for allowing other code to declare pointers only, since the compiler does not need to know the full details just to declare a pointer. But a forward declaration can't be used for creating actual object instances of the class. That is why you are getting errors about an incomplete type. From main()'s perspective, it has no idea what gun actually looks like, so it can't create a full instance of it.
The implementation of the methods for the gun class needs to be in the gun's source file, which can #include the header file to validate and access the class members.
gun.h
#ifndef gun_h
#define gun_h
class gun
{
private:
int stuff;
public:
void doStuff();
};
#endif
gun.cpp
#include "gun.h"
#include <iostream>
void gun::doStuff()
{
std::cout << stuff << std::endl;
}
Now, in main() (or any other source file), you can #include the header file and use the class as needed:
#include "gun.h"
int main()
{
gun *mygun = new gun;
mygun->doStuff();
delete mygun;
return 0;
}
In gun.h
#ifndef GUN_H_
#define GUN_H_
// You can use #pragma once too here
class gun
{
private:
int stuff;
public:
void doStuff();
};
#endif
In gun.cpp file
#include "gun.h"
void gun::doStuff()
{
cout << stuff << endl;
}
and then main.cpp
#include "gun.h"
int main() {
//your code using the class
gun *mygun = new gun;
mygun->doStuff();
return 0;
}
and you can compile and test using
g++ -o prg_name gun.cpp main.cpp && ./prg_name

Why do C++ member functions defined in a class not produce duplicate symbols, whereas they do in C?

C Example
bb.c:
#include "bb.h"
#include <stdio.h>
void bb() {
printf("aa()...\n");
aa();
}
main.c:
#include "aa.h"
#include "bb.h"
int main(int argc, const char** argv) {
aa();
bb();
return 0;
}
aa.h:
#ifndef aa_h
#define aa_h
#include <stdio.h>
void aa() {
printf("aa()...\n");
}
#endif // aa_h
bb.h:
#ifndef bb_h
#define bb_h
#include "aa.h"
void bb();
#endif // bb_h
C Result
Compiled with clang main.c bb.c:
duplicate symbol _aa in:
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/main-OsFJVB.o
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/bb-OkcMzn.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
C++ Example
b.cpp:
#include "b.hpp"
void b::do_something_else() {
std::cout << "b::do_something_else() being called..." << std::endl;
a a;
a.doit();
}
main.cpp:
#include "a.hpp"
#include "b.hpp"
int main() {
a a;
b b;
a.doit();
b.do_something_else();
return 0;
}
a.hpp:
#ifndef a_hpp
#define a_hpp
#include <iostream>
class a{
public:
void doit() {
std::cout << "a::doit() being called..." << std::endl;
}
};
#endif // a_hpp
b.hpp:
#ifndef b_hpp
#define b_hpp
#include "a.hpp"
#include <iostream>
class b{
public:
void do_something_else();
};
#endif // b_hpp
C++ Result
The above compiles fine with clang++ main.cpp b.cpp and the output to the program is:
a::doit() being called...
b::do_something_else() being called...
a::doit() being called...
Questions
Why does the duplicate error not occur with the C++ version?
Does the fact that the function void a::doit() is defined in the header file rather than a source file mean that the compiler will automatically inline the function?
In C++ class methods are not top-level symbols, but are effectively scoped names within their class hierarchy.
This means that you have defined in C++ two doit() methods, a::doit() and b::doit()
In C, you have attempted to define one aa() function twice.
Note that C++ will give an error too if you define the doit() method twice, within the scope of the same class.
#include <iostream>
class a {
public:
void doit() {
std::cout << "hello" << std::endl;
}
void doit() {
std::cout << "goodbye" << std::endl;
}
};
leads to
ed.cpp:11:8: error: ‘void a::doit()’ cannot be overloaded
void doit() {
^
ed.cpp:7:8: error: with ‘void a::doit()’
void doit() {
^
In your C example, aa is defined twice, which violates the "one definition rule". This would be equally true if it were C++.
In your C++ example, a::doit is defined twice, but it is implicitly declared inline. Member functions defined within a class are implicitly inline per [dcl.fct.spec]/3:
A function defined within a class definition is an inline function. ...
inline functions are an exception to the one definition rule (in fact, this is the only meaning of inline required by the standard) per [basic.def.odr]/5.
There can be more than one definition of a ... inline function with external linkage (7.1.2) ... in a program, provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. ...
The requirements essentially boil down to a requirement that the definitions be identical in every translation unit where they appear.
Had you declared aa as inline, similar rules would have applied and your code would have compiled and worked as expected.
Why does the duplicate error not occur with the C++ version?
Because there is no duplication. C++ member functions are scoped by the class they are defined in. b::doit() isn't a duplicate of a::doit().
Does the fact that the function void a::doit() is defined in the header file rather than a source file mean that the compiler will automatically inline the function?
No, but it means it is possible.

c++ undefined reference to vtable

I'm learning C++. I'm trying to do an exercise where I define several implementations of a pure virtual class with a single function. I'm having trouble linking the class that uses these implementations.
==> BasicMath.h <==
#ifndef BASIC_MATH_H
#define BASIC_MATH_H
#include<string>
#include<vector>
class BasicMath { };
#endif // BASIC_MATH_H
==> Operation.h <==
#ifndef OPERATION
#define OPERATION
#include<string>
#include<vector>
class Operation {
public:
virtual void perform(std::vector<std::string> vec) = 0;
};
#endif // OPERATION
==> Sum.h <==
#ifndef SUM_H
#define SUM_H
#include "Operation.h"
class Sum: public Operation {
public:
void perform(std::vector<std::string> vec);
};
#endif // SUM_H
==> BasicMath.cpp <==
#ifndef BASIC_MATH_C
#define BASIC_MATH_C
#include <string>
#include <vector>
#include <iostream>
#include "BasicMath.h"
#include "Sum.h"
int main(int argc, char* argv[]) {
Sum op;
}
#endif // BASIC_MATH_C
==> Sum.cpp <==
#ifndef SUM_C
#define SUM_C
#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"
void Sum::perform(std::vector<std::string> vec) {
using namespace std;
int total = 0;
cout << "Total: " << total << "\n";
};
#endif // SUM_C
Compilation:
$ g++ -c Sum.cpp
$ g++ -o BasicMath BasicMath.cpp
/tmp/cc1VXjNl.o:BasicMath.cpp:(.text$_ZN3SumC1Ev[Sum::Sum()]+0x16): undefined reference to `vtable for Sum'
collect2: ld returned 1 exit status
I'm 95% sure I'm doing at least one foolish thing here - but my brain is refusing to tell me what.
I have see this question but have not managed to fix my issue.
I Just encountered the same problem, but my problem was that I had not written the destructor code in my .cpp file.
class.h:
class MyClass {
public:
MyClass();
virtual ~MyClass();
};
class.cpp:
MyClass::MyClass() {}
It just gave me the vtable error message, and implementing the (empty) destructor solved the problem.
[Edit] Thus, the corrected class file looks like this:
MyClass::MyClass() {}
MyClass::~MyClass() {}
You're not including the Sum.o object file on your compile&link line (second g++ use).
That error also happens if you forget the = 0 for pure virtual functions
Error:
class Base {
public:
virtual void f();
};
class Derived : public Base {
public:
virtual void f() {}
};
int main() {
Derived d;
Base *b = &d;
(void)b;
}
No error:
class Base {
public:
virtual void f() = 0;
};
This is because without the = 0, C++ does not know that it is a pure virtual function, treats it as a declaration, expecting a later definition.
Tested on g++ 5.2.1.
Tested as of GCC 11.2.0, the error message changed to:
undefined reference to `typeinfo for Base'
command:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
A couple of people have already pointed out the solution to the problem you've seen.
I'll add something rather different. You only need header guards in your headers. You've included them in your source files as well, where they really don't make sense. For example, I've commented out the lines you really don't need (or even want) in sum.cpp:
//#ifndef SUM_C
//#define SUM_C
//
#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"
void Sum::perform(std::vector<std::string> vec) {
using namespace std;
int total = 0;
cout << "Total: " << total << "\n";
};
//#endif // SUM_C
Just FWIW, instead of perform, I'd use operator():
class Operation {
public:
virtual void operator()(std::vector<std::string> vec) = 0;
};
and (obviously) that's also what you'd overload for Sum. To use it, instead of something like:
Sum op;
op.perform();
You'd use something like:
Sum op;
op();
This is particularly convenient when you combine your class with others (e.g., those in the standard library) that invoke operations like functions, whether they're really functions, or "functors" (classes like this, that overload operator() so syntactically they can be used almost like functions).
I normally encounter this error when I accidentally forget the =0 at the end of one of my functions in a pure virtual class.
You're just compiling BasicMath.cpp without Sum.cpp - your linker has no idea about Sum.cpp. You'll need to compile them both together, i.e. Sum.cpp BasicMath.cpp in one go, or you can compile the .cpp files independently and then create the executable by calling g++ with both .o files.
I have met the problem same as yours , and I solved this problem by adding three lines in the CMakeLists.txt , that is:
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)