I'm having difficulty interpreting some of my results, which I would expect to behave the same but are not.
I am trying to write a method that returns a function pointer getPtrFn
I have a main.c file reading
#include <iostream>
#include "test.hpp"
int main(int argc, char* argv[]){
Test test;
void (*fPtr)(void) = test.getPtrFn();
return 0;
}
A test.hpp file that reads
#ifndef _test_h
#define _test_h
class Test {
private:
void (*ptrFn)(void);
public:
Test(){};
void (*getPtrFn(void))(void){
return ptrFn;
};
~Test();
};
#endif
And a test.cpp file that reads
#include "test.hpp"
Test::~Test(){}
This runs fine. However, when I move the implementation for *getPtrFn(void) to the implementation file (revised files shown below),
test.hpp:
#ifndef _test_h
#define _test_h
class Test {
private:
void (*ptrFn)(void);
public:
Test(){};
void (*getPtrFn(void))(void);
~Test();
};
#endif
test.cpp:
#include "test.hpp"
void (Test::*getPtrFn)(void){
return ptrFn;
};
Test::~Test(){}
I get the compile error
test.cpp:16:9: error: use of undeclared identifier 'ptrFn'
My understanding of the language syntax is that they would be treated the same. So what gives?
-Jeff
You need
void(*Test::getPtrFn(void))(void)
{
return ptrFn;
}
instead of void (Test::*getPtrFn)(void){...}. void (Test::*getPtrFn)(void) is the declaration of getPtrFn as a pointer-to-Test-member-function taking no parameters (void) and returning void, so after you put the braces { ... } you get a compile-time error (its like trying to declare int i{/*some statemets*/}).
Also, and don't forget to keep the declaration
void(*getPtrFn(void))(void);
in your header (right now it seems you don't have it, did you cut/pasted it?).
Quite a horrible thing to look at... So really, use a type alias, it makes your code much cleaner.
using PTRFN = void(*)(void); // or typedef void(*PTRFN)(void);
class Test {
private:
PTRFN ptrFn;
public:
PTRFN getPtrFn(void);
Test(){};
~Test(){};
};
PTRFN Test::getPtrFn(void) // clear an concise
{
return ptrFn;
}
In case you really really want to be able do decipher every kind of pointer declaration you can think of, try looking at the clockwise/spiral rule, I found it extremely useful, clear and easy to understand. Then test your knowledge at cdecl.org.
Related
There's the main.cpp that has lots of Log prinkled wherever:
#include "utils.hpp"
...//some code
int main(){
int a = 0;
int b = 0;
util::LogClass::Log("Initial","something);
//some more code
util::LogClass::Log("Mid","something");
//some more code
util::LogClass::Log("Middle","something");
}
And the LogClass is defined like this in utils.hpp:
namespace util{
class LogClass{
public:static bool LOG_ENABLED;
public: static void Log(std::string tag, std::string message){
if(LOG_ENABLED){
std::cerr << tag+": "+message <<std::endl;}
}
}
bool LogClass::LOG_ENABLED=true;
}
I was thinking I would be able to do this in main.cpp:
#include "utils.cpp"
util::LogClass::LOG_ENABLE=false;
int main(){ //the previous main function}
*the above code actuallly gives an error saying: redefinition of ‘bool util::LogClass::LOG_ENABLED’
bool util::LogClass::LOG_ENABLE=false *
but, if I move it inside the main:
#include "utils.cpp"
int main(){ util::LogClass::LOG_ENABLED=false; //the previous main function}
then the code compiles fine. So my question is why can't I enable it outside the main() function even if it is a static member, and why does the (g++) compiler takes it as a redefinition?
You can only statically initialize a variable at the point where it is getting defined. The initialization inside the main function is dynamic, so that's fine.
I agree that the compiler error is weird though - the compiler might be trying to auto-deduct the "missing" type that should be there for a redefinition.
I've seen similar questions, but not quite like the predicament I find myself in. I'm working with someone else's code, and their structure is like this.
//db_manager.h
class db_manager
{
class error;
bool logError(error::def_enum::Value v, string msg);
bool read(int id);
}
//db_manager.cpp
#include db_manager.h
bool logError(error::def_enum::Value v, string msg)
{
return error::logError(v, msg);
}
bool read(int id)
{
//do db access stuff
return true;
}
//error.h
#include db_manager
class error
{
bool read(int id);
}
//error.cpp
#include error.h
bool read(int id)
{
return db_manager::read(id);
}
bool logError(error::def_enum::Value v, string msg)
{
//do error service stuff
}
This is a pretty obvious simplification, but hopefully it demonstrates the issue.
When I compile, I get a lot of incomplete type errors whenever error is used in db_manager.cpp, and I can't include the relevant header files from error into db_manager.cpp, because then I have to add it to db_managers cmake dependencies, which means I have to list it in package.xml, and then it gets upset from the circular dependency. How can I get around this? If I could use error's members in db_manager without making error a dependency, I'd be good, I think, but I just can't figure out how to do that. I've seen many other forward-declaration questions on here, but for all of them, the declared class usage isn't very deep. Here I'm using class members, not just declaring a class pointer like other questions.
I definitely could use help, I just don't see any logical way to do this without completely scrapping the error package and writing a new one.
Edit: also, I simplified this out, but maybe I shouldn't have. error and db_manager are in two separate packages.
First: Your example is very bad. Please provide a minimum working example. I understand what your problem is (circular dependency), but your example is not showing this Problem. This is something you have to solve on an architectural level. You can't solve this inside CMake.
Depending on the Code you have shown you don't need to include db_manager.h in error.h, since you are not using anything from db_manager during the declaration of class Error. You only need to include it inside error.cpp, since there you are using one static method from db_manager. That way you don't have any circular dependency.
I have added a minimum working example below which compiles without any errors.
error.h
#ifndef _ERROR_H_
#define _ERROR_H_
#include <string>
class Error
{
public:
enum def_enum{ Val1, Val2};
bool read(int id);
static bool logError(def_enum v, std::string msg);
};
#endif /* _ERROR_H_ */
error.cpp
#include "error.h"
#include "db_manager.h"
bool Error::read(int id)
{
return db_manager::read(id);
}
bool Error::logError(Error::def_enum v, std::string msg)
{
//do error service stuff
return true;
}
db_manager.h
#ifndef _DB_MANAGER_H_
#define _DB_MANAGER_H_
#include <string>
#include "error.h"
class db_manager
{
public:
static bool logError(Error::def_enum v, std::string msg);
static bool read(int id);
};
#endif /* _DB_MANAGER_H_ */
db_manager.cpp
#include "db_manager.h"
bool db_manager::logError(Error::def_enum v, std::string msg)
{
return Error::logError(v, msg);
}
bool db_manager::read(int id)
{
//do db access stuff
return true;
}
main.cpp
#include "db_manager.h"
#include "error.h"
int main(){
db_manager::read(1);
db_manager::logError(Error::Val1, "Test");
Error e;
e.read(2);
return 0;
}
CMakeLists.txt
project(db_manager)
add_executable(executable main.cpp db_manager.cpp error.cpp)
I'm a beginner with C++
I'm having a trouble when I set the header class values.
CalucateNumbers::CalucateNumbers() {
ResetValues();
}
void CalucateNumbers::ResetValues() {
firstNumber = 0;
secondNumber = 8;
}
CalucateNumber is missing exception specification noexcept
Help please?
This is the C plus plus Code file with the name FBullCowGame.cpp
#include "FBullCowGame.hpp"
FBullCowGame::FBullCowGame() {
Reset();
}
void FBullCowGame::Reset() {
CurrentTries = 0;
MaxTries = 8;
}
This is the header file with the name FBullCowGame.hpp
#ifndef FBullCowGame_hpp
#define FBullCowGame_hpp
#include <stdio.h>
#include <string>
#endif /* FBullCowGame_hpp */
class FBullCowGame {
public:
void Reset(); // TODO Make a reset void
// Not important.., The important is this ^^
private:
int CurrentTries;
int MaxTries;
};
Here is the MCVE on godbolt.
You were incorrect when you said "Yes it does" when asked whether the definition matches the header. It does not match the header, because it's not even present in the header!
Your class FBullCowGame doesn't declare a custom constructor, so the compiler created a default one. You then try to create a custom one, and the compiler thinks you're trying to implement the default constructor (which happens to be noexcept), so it says "This redeclaration doesn't match the implicit declaration."
Your real problem is that you forgot to tell the compiler "I'm going to give this class a custom constructor."
class FBullCowGame {
public:
FBullCowGame(); // <----- you forgot this
void Reset(); // TODO Make a reset void
// Not important.., The important is this ^^
private:
int CurrentTries;
int MaxTries;
};
(You also have a problem with the scope of the #ifdef guard in your header file.)
That's a very misleading error message. The problem is that the class definition does not declare a default constructor, but the source code attempts to implement one. To fix this, add a declaration for the default constructor to the class definition.
I am pursuing some interest in c++ programming by way of self instruction. I am working on some basic stuff for now and am currently having issue getting my classes talking/instantiated?.
I am trying to get my main cpp file to compile alongside a header and call to some class functions through the main using a more efficient command method.
I am stuck and would appreciate some help. I will include both files. I am just trying to get a return value from the header by calling the function.
error:
main.cpp:6.21 error: cannot call member function 'void myClass::setNumber(int) without object
the code works when compiled with the main, so it is something with the 'scope resolution operator' i think. First is main.cpp
#include <iostream>
#include "myClass.h"
using namespace std;
int main(){
myClass::setNumber(6);
{
return number;
}
}
Then my header file myClass.h
// MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
class myClass {
private:
int number;//declares the int 'number'
float numberFloat;//declares the float 'numberFloat
public:
void setNumber(int x) {
number = x;//wraps the argument "x" as "number"
}
void setNumberFloat(float x) {
numberFloat = x;
}
int getNumber() {//defines the function within the class.
number += 500;
return number;
}
float getNumberFloat() {//defines the function
numberFloat *= 1.07;
return numberFloat;
}
};
#endif
Any help?
The error message says everything:
cannot call member function 'void myClass::setNumber(int)' without object
You need to create an object first:
myClass obj;
then call the class method on that object:
obj.setNumber(6);
The value 6 will get assigned to the number field of the obj variable.
I am having trouble in my C++ code where I have to make a binary heap. It works fine as long as I had the "main" function inside of my "MyHeap.h" file but my professor wants it to run in a separate test file. For some reason the code doesn't want to run whenever I try to put the main function outside of the "MyHeap.h" file. When it runs I get the following error:
error C2143: syntax error: missing';' before '<'
I looked at my code and this is where it says there is an error but I can't see anything.
// MyHeap.h
#ifndef _MYHEAP_H
#define _MYHEAP_H
#include <vector>
#include <iterator>
#include <iostream>
class Heap {
public:
Heap();
~Heap();
void insert(int element);
int deletemax();
void print();
int size() { return heap.size(); }
private:
int left(int parent);
int right(int parent);
int parent(int child);
void heapifyup(int index);
void heapifydown(int index);
private:
vector<int> heap;
};
#endif // _MYHEAP_H
So like I said whenever I have the the int main function right after the private class, it will work just fine. Now when I implement it into my test file which is this:
#include "MyHeap.h"
#include <vector>
#include <iostream>
int main()
{
// Create the heap
Heap* myheap = new Heap();
myheap->insert(25);
myheap->print();
myheap->insert(75);
myheap->print();
myheap->insert(100);
myheap->print();
myheap->deletemax();
myheap->print();
myheap->insert(500);
myheap->print();
return 0;
}
It keeps popping up the errors, any ideas on I could go about fixing this problem so that my code can run from a test file?
Use std::vector instead of vector.
The compiler is complaining it doesn't know about vector.
Since it lives in std namespace, the safest solution is to prefix with std.