declaring class variable c++ [closed] - c++

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
So I'm at a complete loss...
In my code I've got
void Parser(FILE* file)
{
Parser par(file);
par.Parse();
}
and I call it in my main function with
Parser(file);
and the header file I've got (which I included in the main file) looks like:
class Parser: public Lexer
{
public:
Parser(FILE* file):Lexer(file);
int Parse();
};
and the error I'm getting is:
p02.cpp: In function 'void Parser(FILE*)':
p02.cpp:20: error: expected ';' before 'par'
p02.cpp:21: error: 'par' was not declared in this scope
make: *** [p02.o] Error 1
What I don't understand is why it is expecting a semicolon before par. Isn't that a legal declaration of a variable for that class?
Edit2: Changing my function name to not be Parser like the class name does not solve this problem. It does give me an extra error telling me that Parser is not declared in this scope, but I cannot see how that is when I've added the include file containing the Parser class right above the declaration for the function.
Edit: My Files
p02.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
#include <string>
#include "p02lex.h"
#include "y.tab.h"
using namespace std;
void Parser(FILE* file)
{
Parser par(file);
par.Parse();
}
int main(int argc, char* argv[])
{
char fileName[255];
switch(argc)
{
case 1:
cout << "Enter the input file name. ";
cin >> fileName;
break;
case 2:
strcpy(fileName, argv[1]);
break;
default:
cout << "Too many arguments!\n";
exit(1);
}
FILE* file = fopen(fileName, "r");
Parser(file);
fclose(file);
return 0;
}
p02lex.l:
#include "p02lex.h"
#define ID 257
...
#define PROGRAM 304
int TokenMgr(int t);
const char* getTokens(int tokenCode);
unsigned lineCount = 1, columnCount = 1;
%}
LETTER [a-z]|[A-Z]
DIGIT [0-9]
%%
// rules defined here, calling TokenMgr()
%%
int TokenMgr(int t)
{
/* int tc = t;
if (t == IDENTIFIER)
{
char s[1024];
ToLower(s, yytext, strlen(yytext));
tc = RW[s];
if (tc == 0)
tc = t;
}
PrintToken(tfs, tc, line, col);
col += yyleng; */ //JEG
printf("Token:Code=%d Name=%10s line=%3u col=%3u Spelling=\"%s\"\n", t, getTokens(t), lineCount, columnCount, yytext);
columnCount += yyleng;
return /* tc */ 0; // JEG
}
Lexer::Lexer(FILE* file)
{
yyin = file;
}
int Lexer::Scan(void)
{
return yylex();
}
const char* getTokens(int tokenCode)
{
switch(tokenCode)
{
case ID:
return "ID";
... // more cases, returning strings
default:
return NULL;
}
}
p02lex.h:
#ifndef p02lex_h
#define p02lex_h 1
#endif
int yylex(void);
class Lexer
{
public:
Lexer(FILE* file);
int Scan(void);
};
p02par.h:
#ifndef p02par_h
#define p02par_h 1
#endif
using namespace std;
#ifdef __cplusplus
extern "C"
#endif
int yyparse(void);
class Parser: public Lexer
{
public:
Parser(FILE* file):Lexer(file){}
void Parse();
// int Scan(void);
};
p02par.y:
#include <stdio.h>
#include "p02lex.h"
#include "p02par.h"
void yyerror(const char* m);
%}
%token PROGRAM
%token ID
%token SEMICOLON
%%
program:
PROGRAM ID SEMICOLON
{ printf("Stuff happens!\n"); }
%%
void yyerror(const char* m)
{
printf("%s\n", m);
}
/*Parser::Parser(FILE* file):Lexer(file)
{
}*/
int Parser::Parse()
{
return yyparse();
}
p02make:
#LEX = flex
#YACC = yacc -d
CC = g++
OBJ = p02.o p02par.o p02lex.o
p02: ${OBJ}
$(CC) -o p02 ${OBJ} -ll -ly
y.tab.h p02par.cpp: p02par.y
yacc -d -v p02par.y
mv y.tab.c p02par.cpp
p02lex.cpp: p02lex.l
lex p02lex.l
mv lex.yy.c p02lex.cpp
p02par.o: p02par.cpp p02par.h
$(CC) -c -g p02par.cpp
p02.o: p02.cpp p02lex.h p02par.h
$(CC) -c -g p02.cpp
p02lex.o: p02lex.cpp p02lex.h y.tab.h
$(CC) -c -g p02lex.cpp

that should be :
Parser(File* file):Lexer(file) {}
Wait I checked that code, rename the function: void Parser(FILE *f) to something else.

You can only include an initializer list in a constructor definition, not a constructor declaration, so it must be followed by a function body (often empty), not a semicolon. There's also a bit of a problem with a name conflict:
void Parser(FILE* file) // here you've defined Parser as the name of a function
{
Parser par(file); // but here you're trying to use it as the name of a class.
par.Parse();
}
Edit: Here's a bit of code that compiles cleanly, at least with the compilers I have handy:
#include <stdio.h>
class Lexer {
FILE *infile;
public:
Lexer(FILE *f) : infile(f) {}
};
class Parser : public Lexer {
public:
Parser(FILE *f) : Lexer(f) {}
void Parse() {}
};
void do_parse(FILE *file) {
Parser p(file);
p.Parse();
}

You need to qualify Parser because the function has the same identifier as the class:
void Parser(FILE* file)
{
class Parser par(file);
par.Parse();
}
You could also rename the function.
You also need braces here:
Parser(FILE* file):Lexer(file) {}

Change
void Parser(FILE* file)
to
Parser::Parser(FILE* file)
Constructors do not have a return type.

Related

function is being redefined somewhere and I cannot see where I am doing it

I am getting this error and I can not figure it out can someone please help explain what I am doing wrong? I have tried removing some of the include statements as well as creating a makefile for my project but I keep getting the same errors
This is my Token.h
#pragma once
#include <string>
#include <iostream>
enum TokenType {
// Reserved Words:
VOID_TOKEN, MAIN_TOKEN, INT_TOKEN, COUT_TOKEN
};
// IMPORTANT: The list above and the list below MUST be kept in sync.
const std::string gTokenTypeNames[] = {
"VOID", "MAIN", "INT", "COUT"
};
class TokenClass {
private:
TokenType mType;
std::string mLexeme;
public:
TokenClass();
TokenClass(TokenType type, const std::string &lexeme);
TokenType GetTokenType() const {
return mType;
}
};
This is my Token.cpp file
#include "Token.h"
TokenClass::TokenClass() {
}
TokenClass::TokenClass(TokenType type, const std::string &lexeme) {
mType = type;
mLexeme = lexeme;
}
TokenType TokenClass::GetTokenType() const {
return mType;
}
and here is my Main.cpp file
#include "Token.h"
int main() {
TokenType tt = VOID_TOKEN;
std::string lexeme = "void";
TokenClass tok1(tt, lexeme);
// std::cout << tok1 << std::endl;
}
and here are the errors I am getting
g++ -std=c++11 -g main.cpp Token.cpp -o Token
Token.cpp:11:11: error: redefinition of ‘TokenType TokenClass::GetTokenType() const’
TokenType TokenClass::GetTokenType() const {
^~~~~~~~~~
In file included from Token.cpp:1:
Token.h:40:12: note: ‘TokenType TokenClass::GetTokenType() const’ previously defined here
TokenType GetTokenType() const {
^~~~~~~~~~~~
make: *** [Makefile:8: main] Error 1
Your error message tells you file named and lines in each file. Line 11 of the CPP and line 40 of the header file.
Delete the body (the stuff in {}) part of thr=e function in the header file )reppacing it with a ;), or delete all mention of the function in the cpp file. Both work.

error C2011: 'SelectorBox' : 'class' type redefinition

I have a problem with a following code:
#ifndef HEADER_H_
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
#endif
//include libraries
#include "Header.h"
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
#include "Header.h"
#include "main.cpp"
void SelectorBox::setSelectorName(string name) //setter
{
name = trimTheString(name);
selectorName = name;
}
void SelectorBox::setAttribute(string key, string value) //setter
{
key = trimTheString(key);
value = trimTheString(value);
attributeMap[key] = value;
}
When I compile a program, it shows many errors (specifically errors 4430 and 2061), but I believe that the main error is:
error C2011: 'SelectorBox' : 'class' type redefinition.
You must define HEADER_H_. You missed second line from below code.
#ifndef HEADER_H_
#define HEADER_H_
...
#endif
You are including the same header twice, first before main second after main, this causes a problem if you don't use proper include guards.
Your include guard is incomplete, so multiple includes of the same header will cause this error. The trick is to check if a header-specific preprocessor name is defined: If not, then define it, else skip the whole header.
The pattern to use is like this
#ifndef GUARD
#define GUARD
/// the actual header contents
#endif
but simply copying it into every header will cause another problem, because its lack of header specificity. The simplest way to find a good name is to derive it from the file name itself. In your case I'd name the header after the class SelectorBox defined in it, so SelectorBox.h would be a good name, and the include guards would look like this:
#ifndef SELECTORBOX_H
#define SELECTORBOX_H
class SelectorBox {
/// etc.
};
#endif
Using multiple headers with the same include guard is much worse than using no include guards at all.
I guess, you have 3 files:
Header.h
main.cpp
FileX.cpp (you didn't disclose the real name of mister X so far)
In main.cpp you are including Header.h, in FileX.cpp you are including Header.h and main.cpp. Let me show a simplified version of what happens here:
The contents of main.cpp gets transformed into
//include libraries
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
Assuming you included string and map and there is another using namespace std; somewhere before your class definition, this could compile without errors.
But now let's see what happens in FileX.cpp. Its contents gets transformed into the following, and I hope you'll see now what the compilers sees: there is more than one definition of the class SelectorBox:
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
//include libraries
class SelectorBox{
public:
string selectorName;
map < string, string > attributeMap;
void setSelectorName(string name);
void setAttribute(string key, string value);
};
string trimTheString(string str); //trimming a string
using namespace std;
int main()
{
vector <SelectorBox> vectorSelectBox;
SelectorBox *selectorBox;
//code
return 0;
}
void SelectorBox::setSelectorName(string name) //setter
{
name = trimTheString(name);
selectorName = name;
}
void SelectorBox::setAttribute(string key, string value) //setter
{
key = trimTheString(key);
value = trimTheString(value);
attributeMap[key] = value;
}
... compilers use to call that a "redefinition".

Arduino: pass function to class, returning String

I'm trying to get my Arduino class to return String messages with all kind of information for logging. With lots of trial and error I manage to pass a reference to the logging function to the class, but can only get a char* but not a String, and I want to be able to send Strings making it so much easier to send back all kinds of data.
I have the first part working already.
The sketch:
#include <Test.h>
#include <string.h>
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
The header file:
#ifndef TEST_h
#define TEST_h
class Test
{
public:
Test(); // The constructor.
void setLogging(void (*)(char*)); // Takes function setting where to log.
void doSomething(char*);
};
#endif
The class:
#include <Test.h>
typedef void (*LogFunction)(char*);
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
void Test::setLogging (void (*f)(char*) ) {
writeLog = f;
return;
}
Now what I want my class to be able to do is send information like this, as String, rather than char* (I also haven't found an easy way of converting "anything" to char* and then concatenating the two or more strings):
writeLog ("HydroMonitorECSensor::setCalibration Receiving calibration - haveCalibration = " + String(haveCalibration));
writeLog ("HydroMonitorECSensor::setCalibration calibratedSlope = " + String(calibratedSlope));
writeLog ("HydroMonitorECSensor::setPins capPos set to " + String(capPos));
Where haveCalibration is a bool (which as String becomes either "true" or "false"), calibratedSlope is a double and capPos is an int. This way I can easily and cleanly send complete lines to the logger. Works great within the main script - not from the class.
I tried simply changing the char* to String and adding #include <string.h> to the library files but it doesn't work.
In Test.cpp I then get void Test::setLogging (void (*f)(String) ) { and in Test.h void setLogging(void (*)(String)); and now I get error messages:
In file included from /home/wouter/Arduino/libraries/Test/Test.cpp:1:0:
/home/wouter/Arduino/libraries/Test/Test.h:10:29: error: expected ',' or '...' before '(' token
void setLogging(void (*)(String)); // Takes function setting where to log.
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:40: error: variable or field 'setLogging' declared void
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:31: error: 'f' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
/home/wouter/Arduino/libraries/Test/Test.cpp:16:34: error: 'String' was not declared in this scope
void Test::setLogging (void (*f)(String) ) {
^
exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).
Suggestions?
Additional info, maybe important: I'm using the Arduino IDE and compile for ESP8266.
You are using the Arduino-provided String class, but didn't include the Arduino.h header in your test.h header file. That causes it to not find the String class and compilation fails.
The following works:
main.cpp:
#include <Arduino.h>
#include <test.hpp>
void writeLog (char* message);
void writeLog (String message);
void setup() {
Serial.begin(115200);
Test t;
t.setLogging(writeLog);
writeLog("Test message!" + String(" .... "));
t.doSomething("This is useful.");
t.doSomething("This as well.\n");
t.doSomething("This is even more useful.\n");
bool b = true;
}
void loop() {
}
void writeLog (char* message) {
Serial.print("char function: ");
Serial.print(message);
}
void writeLog (String message) {
Serial.print("String function: ");
Serial.println(message);
}
test.hpp:
#ifndef TEST_h
#define TEST_h
#include <Arduino.h> //for "String" class
//Typdef for the log function. Takes a String, returns nothing
typedef void (*LogFunction)(String);
class Test
{
public:
Test(); // The constructor.
// void setLogging(void (*)(char*)); // Takes function setting where to log.
void setLogging(LogFunction); //use the typedef here
void doSomething(char*);
};
#endif
test.cpp:
#include <test.hpp>
LogFunction writeLog;
Test::Test () {
}
void Test::doSomething (char* s) {
// Do something useful and log the result.
writeLog(s);
}
//void Test::setLogging (void (*f)(char*) ) {
void Test::setLogging (LogFunction f) { //also use typedef here
writeLog = f;
return;
}
Among other things that may arise, the compiler tells you that it cannot resolve identifier String.
This can have several reasons: First, you write String, and not string (note the capital letter in your writing). Second, if you write string and not std::string, it cannot be resolved unless you have either declared using namespace std (which is not the preferred variant for several reasons) or using std::string. Third, class std::string is declared in header <string>, which is something different than <string.h>.
So I'd write #include <string> and use then std::string.

G++ - Undefined Reference to member function that is defined

I am currently working on a virtual run time environment program that is at a very early stage, i am prevented from continuing my work due to a linker error when using my makefile, provided below. The error i am receiving is:
g++ controller.o processor.o test.o -o final
controller.o: In function `Controller::run()':
controller.cpp:(.text+0x1e0): undefined reference to
Processor::codeParams(char)'
controller.o: In function `Controller::fetch()':
controller.cpp:(.text+0x290): undefined reference to `Controller::pc'
controller.cpp:(.text+0x299): undefined reference to `Controller::pc'
collect2: error: ld returned 1 exit status
makefile:16: recipe for target 'final' failed
make: *** [final] Error 1
I am unsure as to why i get this error as i thought i had defined these things in the source file corresponding to the header. All files will be given below so that the program can be compiled.
test.cpp:
#include <iostream>
#include <vector>
#include "includes/controller.h"
using namespace std;
int main()
{
vector<char> prog = {0x0};
Controller contr(prog);
cout << "Error Code: " << contr.run() << endl;
return 0;
}
controller.cpp:
/*
Author(s): James Dolan
File: controller.cpp
Build: 0.0.0
Header: includes/controller.h
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#include "includes/controller.h"
Controller::Controller(vector<char> prog)
{
printf("Program:"); //Display program
for(auto i : program)
{
printf("%02X", i);
}
printf("\n");
Controller::program = program;
}
Controller::~Controller ()
{
}
int Controller::run()
{
bool runFlag = true;
int errorCode = 0;
char curCode;
vector<char> curInstr;
int paramRef;
while(runFlag)
{
curCode = fetch();
printf("curCode:%02X\n", curCode);
curInstr.push_back(curCode);
paramRef = proc.codeParams(curCode);
if (paramRef == 0xffff){runFlag = false; continue;} //Check if shutdown signal was returned, if so shutdown
printf("opcode good\n");
for(int i; i<paramRef; i++){curInstr.push_back(fetch());}
}
return errorCode;
}
char Controller::fetch()
{
return program[pc++]; //Return next instruction then increment the program counter
}
controller.h:
/*
Author(s): James Dolan
File: controller.h
Source: ../controller.cpp
DoLR: 21:39 11/1/2017
Todo: n/a
*/
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <iostream>
#include <vector>
#include <cstdlib>
#include "processor.h"
using namespace std;
class Controller{
public:
Controller(vector<char> prog);
~Controller();
int run();
protected:
private:
vector<char> program;
static int pc;
char fetch();
Processor proc();
};
#endif
processor.cpp:
#include "includes/processor.h"
Processor::Processor()
{
}
Processor::~Processor()
{
}
int codeParams(char code)
{
switch(code)
{
case 0x0: //Halt
return 0;
default:
printf("[ERROR!] Invalid opcode [%02X]", code);
return 0xffff; //Return shutdown signal
}
}
processor.h:
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include <iostream>
#include <cstdlib>
class Processor{
public:
Processor();
~Processor();
int codeParams(char code);
protected:
private:
};
#endif
All if any help is appreciated massively as it will help me to continue with my passion of developing a fully fledged open-source virtual runtime enviroment like the java vm, thank you for your time.
In Controller.cpp you need a int Controller::pc; or int Controller::pc = 0;
In the header file you declared a static int named pc that exists somewhere. It needs to actually exist in a translation unit somewhere (in this case Controller.cpp) so that when the linker tries to find it... it exists.
In Processor.cpp your signature should look like int Processor::codeParams(char code) to let the compiler know that is Processor's codeParams and not a random function named codeParams that happens to also take a character.
For the member function Processor::codeParams you should define it as:
int Processor::codeParams(char code)
// ~~~~~~~~~~~
{
...
}
Otherwise it's just a normal (non–member) function.
For the static member Controller::pc you should define it outside of the class definition, in controller.cpp.
// Controller.h
class Controller {
...
private:
static int pc;
};
// controller.cpp
int Controller::pc;

using C++ with namespace in C

Using Eclpse on Linux I have defined a C++ class, named ABC (ABC.hpp):
#ifndef ABC_HPP_
#define ABC_HPP_
#include <stdio.h>
// namespace my { <---- COMMENTED OUT
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
// } /* namespace my */ <---- COMMENTED OUT
#endif /* ABC_HPP_ */
and its implementation is (ABC.cpp):
#include "ABC.hpp"
// using namespace my; <---- COMMENTED OUT
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
To use this class in C programs, I have created a layer containing these methods (ABCwrapper.h):
typedef void CABC;
#ifdef __cplusplus
extern "C" {
#endif
CABC* create_abc();
void call_abc_methods(const CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
} // extern "C"
#endif
and
#include "ABC.hpp"
#include "ABCWrapper.h"
extern "C" {
CABC* create_abc() {
ABC* abc = new ABC();
return (ABC*)abc;
}
void call_abc_methods(const CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = (ABC*)p_abc;
delete abc;
}
}
That's fine and I can use the ABC class instance. But what about the define the ABC class in a name space, let's say "my"? If I remove the comment signs from all name space lines the IDE complains saying that the "Type 'ABC' could not be resolved".
If I want to extend my C++ library I have to use name space for my classes but then I don't know how to use in wrappers. Please, help me to solve this mystery.
Thank you.
SK
Some mostly minor nitpicks about the code. You've already got the details of the solution with an active namespace, but there are various minor issues that should be addressed.
You would be better off introducing an incomplete type, typedef struct CABC CABC; (in place of typedef void CABC;), so that you get some type safety in the C code. This would prevent you passing a random FILE *, for example, to the C interface functions, which using void won't.
When you use the incomplete type, you should use reinterpret_cast<ABC *>(abc) in the C wrapper functions instead of C-style casts. The compiler then shows up a problem with const-ness in the call_abc_methods() function; the argument should not be const (but the C-style cast hid the problem).
Additionally, your ABC.hpp header shows a common (minor) mistake; it includes an extraneous header (#include <stdio.h>) that is not needed to use the header safely. That line should only appear in the implementation file, ABC.cpp, where the code uses the services of <stdio.h>. Most headers should #include only those other headers necessary to make the header usable on its own. They should not include random other headers.
Here's a complete working program — which has a lot of files. There are 3 headers:
ABC.hpp — declaring class ABC.
ABCwrapper.h — declaring the C interface to class ABC.
ABCprogram.h — bilingual header declaring other functions.
There is 1 C file:
ABCuser.c — there must be some C code that needs to use the C interface to class ABC to make the whole exercise worthwhile, and this is it.
There are 3 C++ files:
ABC.cpp — defining class ABC.
ABCwrapper.cpp — defining the C interface to class ABC.
ABCmain.cpp — the main program in a bilingual system should normally be written in C++.
And there's a makefile.
ABC.hpp
#ifndef ABC_HPP_INCLUDED
#define ABC_HPP_INCLUDED
namespace abc_library {
class ABC {
private:
int m_number;
public:
ABC(int p_number);
void doSomething();
virtual ~ABC();
};
} /* namespace abc_library */
#endif /* ABC_HPP_INCLUDED */
ABCwrapper.h
#ifndef ABCWRAPPER_H_INCLUDED
#define ABCWRAPPER_H_INCLUDED
typedef struct CABC CABC; // Pointer to this ncomplete type used in C code
#ifdef __cplusplus
extern "C" {
#endif
CABC *create_abc(int val);
void call_abc_methods(CABC *p_abc);
void destroy_abc(CABC *p_abc);
#ifdef __cplusplus
}
#endif
#endif /* ABCWRAPPER_H_INCLUDED */
ABCprogram.h
#ifndef ABCPROGRAM_H_INCLUDED
#define ABCPROGRAM_H_INCLUDED
#if defined(__cplusplus)
extern "C" {
#endif
extern int c_code_function(int init);
#if defined(__cplusplus)
}
#endif
#endif /* ABCPROGRAM_H_INCLUDED */
ABCuser.c
#include "ABCwrapper.h"
#include "ABCprogram.h"
int c_code_function(int init)
{
CABC *abc = create_abc(init);
call_abc_methods(abc);
destroy_abc(abc);
return 0;
}
ABC.cpp
#include "ABC.hpp"
#include <stdio.h>
using namespace abc_library;
ABC::ABC(int p_number) {
this->m_number = p_number;
}
ABC::~ABC() {
this->m_number = -1;
}
void ABC::doSomething() {
printf("doing something (%d)\n", this->m_number);
}
ABCwrapper.cpp
#include "ABC.hpp"
#include "ABCwrapper.h"
using namespace abc_library;
extern "C" {
CABC *create_abc(int val) {
ABC* abc = new ABC(val);
return reinterpret_cast<CABC*>(abc);
}
void call_abc_methods(CABC *p_abc) {
ABC *abc = reinterpret_cast<ABC *>(p_abc);
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
ABC* abc = reinterpret_cast<ABC *>(p_abc);
delete abc;
}
}
ABCmain.cpp
#include "ABCprogram.h"
int main()
{
return c_code_function(39);
}
makefile
CC = gcc # /usr/bin/gcc
CXX = g++
RM_FR = rm -fr --
WFLAGS = -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition
SFLAGS = -std=c99
OFLAGS = -g -O3
UFLAGS = # Set on make command line only
OXXFLAGS = -g -O3
SXXFLAGS = -std=c++11
WXXFLAGS = -Wall -Wextra
UXXFLAGS = # Set on make command line only
LDFLAGS =
LDLIBS =
CFLAGS = ${OFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
CXXFLAGS = ${OXXFLAGS} ${SXXFLAGS} ${WXXFLAGS} ${UXXFLAGS}
PROGRAM = abc
FILES.cpp = \
ABC.cpp \
ABCmain.cpp \
ABCwrapper.cpp
FILES.c = \
ABCuser.c
FILES.h = \
ABCprogram.h \
ABCwrapper.h
FILES.o = ${FILES.cpp:.cpp=.o} ${FILES.c:.c=.o}
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CXX} -o $# ${CXXFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
clean:
${RM_FR} *.o *.dSYM core a.out
depend:
mkdep ${FILES.cpp} ${FILES.c}
# DO NOT DELETE THIS LINE or the blank line after it -- make depend uses them.
ABC.o: ABC.cpp
ABC.o: ABC.hpp
ABCmain.o: ABCmain.cpp
ABCmain.o: ABCprogram.h
ABCuser.o: ABCprogram.h
ABCuser.o: ABCuser.c
ABCuser.o: ABCwrapper.h
ABCwrapper.o: ABC.hpp
ABCwrapper.o: ABCwrapper.cpp
ABCwrapper.o: ABCwrapper.h
In ABCWrapper.cpp, above the extern "C" { line, add:
using my::ABC;
or
using namespace my;
john's suggestion (replace all instances of ABC with my::ABC in ABCWrapper.cpp) also works.
You have to set the scope for your ABC class. So replace all the ABC class as my::ABC except in the class declaration.
extern "C" {
CABC* create_abc() {
my::ABC* abc = new my::ABC();
return (my::ABC*)abc;
}
void call_abc_methods(const CABC *p_abc) {
my::ABC* abc = (my::ABC*)p_abc;
abc->doSomething();
}
void destroy_abc(CABC *p_abc) {
my::ABC* abc = (my::ABC*)p_abc;
delete abc;
}
}