I am trying to use forward declarations in header files to reduce the number of #include used and hence reduce dependencies when users include my header file.
However, I am unable to forward declare where namespaces are used. See example below.
File a.hpp:
#ifndef __A_HPP__
#define __A_HPP__
namespace ns1 {
class a {
public:
a(const char* const msg);
void talk() const;
private:
const char* const msg_;
};
}
#endif //__A_HPP__
File a.cpp:
#include <iostream>
#include "a.hpp"
using namespace ns1;
a::a(const char* const msg) : msg_(msg) {}
void a::talk() const {
std::cout << msg_ << std::endl;
}
File consumer.hpp:
#ifndef __CONSUMER_HPP__
#define __CONSUMER_HPP__
// How can I forward declare a class which uses a namespace
//doing this below results in error C2653: 'ns1' : is not a class or namespace name
// Works with no namespace or if I use using namespace ns1 in header file
// but I am trying to reduce any dependencies in this header file
class ns1::a;
class consumer
{
public:
consumer(const char* const text) : a_(text) {}
void chat() const;
private:
a& a_;
};
#endif // __CONSUMER_HPP__
Implementation file consumer.cpp:
#include "consumer.hpp"
#include "a.hpp"
consumer::consumer(const char* const text) : a_(text) {}
void consumer::chat() const {
a_.talk();
}
Test file main.cpp:
#include "consumer.hpp"
int main() {
consumer c("My message");
c.chat();
return 0;
}
UPDATE:
Here is my very contrived working code using the answer below.
File a.hpp:
#ifndef A_HPP__
#define A_HPP__
#include <string>
namespace ns1 {
class a {
public:
void set_message(const std::string& msg);
void talk() const;
private:
std::string msg_;
};
} //namespace
#endif //A_HPP__
File a.cpp:
#include <iostream>
#include "a.hpp"
void ns1::a::set_message(const std::string& msg) {
msg_ = msg;
}
void ns1::a::talk() const {
std::cout << msg_ << std::endl;
}
File consumer.hpp:
#ifndef CONSUMER_HPP__
#define CONSUMER_HPP__
namespace ns1
{
class a;
}
class consumer
{
public:
consumer(const char* text);
~consumer();
void chat() const;
private:
ns1::a* a_;
};
#endif // CONSUMER_HPP__
File consumer.cpp:
#include "a.hpp"
#include "consumer.hpp"
consumer::consumer(const char* text) {
a_ = new ns1::a;
a_->set_message(text);
}
consumer::~consumer() {
delete a_;
}
void consumer::chat() const {
a_->talk();
}
File main.cpp:
#include "consumer.hpp"
int main() {
consumer c("My message");
c.chat();
return 0;
}
To forward declare class type a in a namespace ns1:
namespace ns1
{
class a;
}
To forward declare a type in multiple level of namespaces:
namespace ns1
{
namespace ns2
{
//....
namespace nsN
{
class a;
}
//....
}
}
Your are using a a member of consumer which means it needs concrete type, your forward declaration won't work for this case.
For nested namespaces, since C++17, you can do
namespace ns1::ns2::nsN
{
class a;
}
Apart to forward-declare the class from within its namespace (as #billz says), remember to either use (prepend) that namespace when referring to the forward-declared class, or add a using clause:
// B.h
namespace Y { class A; } // full declaration of
// class A elsewhere
namespace X {
using Y::A; // <------------- [!]
class B {
A* a; // Y::A
};
}
Ref: Namespaces and Forward Class Declarations
Related
I'm trying to learn Inheritance mechanism in C++, I have made a Bancnote(Bills) class, and I want to make a class Card inheriting all the functions and variables from Class Bancnote.
And I get this type of error :
include\Card.h|6|error: expected class-name before '{' token|
BANCNOTE.H
#ifndef BANCNOTE_H
#define BANCNOTE_H
#include <iostream>
#include "Card.h"
using namespace std;
class Bancnote
{
public:
Bancnote();
Bancnote(string, int ,int ,int );
~Bancnote( );
int getsumacash( );
void setsumacash( int );
int getsumaplata( );
void setsumaplata( int );
int getrest( );
void setrest( int );
string getnume( );
void setnume( string );
void ToString();
protected:
private:
string nume;
int sumacash;
int rest;
static int sumaplata;
};
#endif // BANCNOTE_H
BANCNOTE.CPP
#include <iostream>
#include "Bancnote.h"
#include "Card.h"
using namespace std;
int Bancnote::sumaplata=0;
Bancnote::Bancnote(string _nume,int _sumacash,int _rest, int _sumaplata )
{
this->nume=_nume;
this->sumacash=_sumacash;
this->rest=_rest;
this->sumaplata=_sumaplata;
}
Bancnote::Bancnote()
{
this->nume="";
this->sumacash=0;
this->rest=0;
this->sumaplata=0;
}
Bancnote::~Bancnote()
{
cout<<"Obiectul"<<"->" <<this->nume<<"<-"<<"a fost sters cu succes";
}
string Bancnote::getnume()
{
return nume;
}
void Bancnote::setnume(string _nume)
{
this->nume=_nume;
}
int Bancnote::getsumacash()
{
return sumacash;
}
void Bancnote::setsumacash(int _sumacash)
{
this->sumacash=_sumacash;
}
int Bancnote::getsumaplata()
{
return sumaplata;
}
void Bancnote::setsumaplata(int _sumaplata)
{
this->sumaplata=_sumaplata;
}
int Bancnote::getrest()
{
return rest;
}
void Bancnote::setrest(int _rest)
{
this->rest=_rest;
}
void Bancnote::ToString()
{
cout<< "-----"<<getnume()<< "-----"<<endl;
cout<<"Suma Cash: "<<this->getsumacash()<<endl;
cout<<"Suma spre plata: "<<this->getsumaplata()<<endl;
cout<<"Restul:"<<this->getrest()<<endl;
}
CARD.H
#ifndef CARD_H
#define CARD_H
#include "Bancnote.h"
class Card: public Bancnote
{
public:
Card();
virtual ~Card();
protected:
private:
};
#endif // CARD_H
You have messed up the includes. What you have is more or less this:
Bancnote.h:
#ifndef BANCNOTE_H
#define BANCNOTE_H
#include "Card.h" // remove this
struct Bancnote {};
#endif
Card.h
#ifndef CARD_H
#define CARD_H
#include "Bancnote.h"
struct Card : Bancnote {}; // Bancnote is not yet declared
// when compiler reaches here
#endif
When in main you include Bancnote.h then this header includes Card.h so you try to declare Card before Bancnote is declared. Actually Bancnote does not need the definition of Card, so simply removing the include should fix it.
PS: there are other issues (see comments below your question). Most importantly it is not clear why a Card is a Bancnote. Second, never put a using namespace std; inside a header! (see here why)
What must the structure of a class look like if it is defined in a separate namespace?
Which parts belong in the header file and which in the cpp file?
How can I make the class accessible only through this specific namespace?
classname.h
#include <iostream>
namespace N {
class classname {
public:
void classmethod();
}
}
classname.cpp
#include "classname.h"
namespace N {
void classname::classmethod() {
std::cout << "classmethod" << std::endl;
}
}
main.cpp
#include "classname.h"
int main() {
N::classname a;
classname b; // Error!
a.classmethod();
return 0;
}
can sombody explain to me why my code will not work, and how to fix it thanks :)
I keep recieving this error :
no 'int burrito::setName()' member function declared in class 'burrito'
My goal is to call a function from a different class file
My main.cpp :
#include <iostream>
#include "burrito.h"
using namespace std;
int main()
{
burrito a;
a.setName("Ammar T.");
return 0;
}
My class header (burrito.h)
#ifndef BURRITO_H
#define BURRITO_H
class burrito
{
public:
burrito();
};
#endif // BURRITO_H
My class file (burrito.cpp):
#include "burrito.h"
#include <iostream>
using namespace std;
burrito::setName()
{
public:
void setName(string x){
name = x;
};
burrito::getName(){
string getName(){
return name;
};
}
burrito::variables(string name){
string name;
};
private:
string name;
};
Your code is a mess. You need to write function prototypes in the header file and function definitions in the cpp file. You are missing some basic coding structures. See below and learn this pattern of coding:
This code should work and enjoy burritos !
main():
#include <iostream>
#include "Header.h"
int main()
{
burrito a;
a.setName("Ammar T.");
std::cout << a.getName() << "\n";
getchar();
return 0;
}
CPP file:
#include "Header.h"
#include <string>
void burrito::setName(std::string x) { this->name = x; }
std::string burrito::getName() { return this->name; }
Header file:
#include <string>
class burrito
{
private:
std::string name;
public:
void setName(std::string);
std::string getName();
//variables(string name) {string name;} // What do you mean by this??
};
Your poor little burrito is confused. Confused burritos can't help much.
You may want your burrito declaration as:
class Burrito
{
public:
Burrito();
void set_name(const std::string& new_name);
std::string get_name() const;
private:
std::string name;
};
The methods could be defined in the source file as:
void
Burrito::set_name(const std::string& new_name)
{
name = new_name;
}
std::string
Burrito::get_name() const
{
return name;
}
The header file only has a constructor for the class. The member functions
setName(string) and getName()
are not declared in the header file and that is why you get the error.
Also, you need to specify the return type for functions.
One way to do this would be
//Header
//burrito.h
class burrito{
private:
string burrito_name;
public:
burrito();
string getName();
void setName(string);
}
//burrito.cpp
#include "burrito.h"
#include <iostream>
using namespace std;
string burrito::getName()
{
return burrito_name;
}
void burrito::setName(string bname)
{
bname =burrito_name;
}
This is a simple example for class in C++,
Save this in burrito.cpp file then compile and run it:
#include <iostream>
#include <string>
using namespace std;
class burrito {
public:
void setName(string s);
string getName();
private:
string name;
};
void burrito::setName(string s) {
name = s;
}
string burrito::getName() {
return name;
}
int main() {
burrito a;
a.setName("Ammar T.");
std::cout << a.getName() << "\n";
return 0;
}
I have a class that I inline'd the constructor and the destructor and I also have a static method for that class. I called that static method inside of the inline destructor, but I'm having a linker error undefined reference for that static method. I'm pretty sure it is compiled and link with the object. Here is the code,
// CFoo.h
namespace barname {
class CFoo
{
public:
CFoo();
~CFoo();
static void fooMethod();
};
inline CFoo::CFoo()
{
}
inline CFoo::~CFoo()
{
fooMethod();
}
}
// SomeOtherSource.cpp
namespace barname
{
void CFoo::fooMethod()
{
}
}
It seems the code is fine and compiling.
Here is a slightly modified working version of the code
Coliru example
#include <iostream>
#include <string>
#include <vector>
namespace barname
{
class CFoo
{
public:
CFoo();
~CFoo();
static void fooMethod();
};
inline CFoo::CFoo()
{
}
inline CFoo::~CFoo()
{
fooMethod();
}
void CFoo::fooMethod()
{
std::cout << "in fooMethod" << std::endl;
}
}
int main()
{
barname::CFoo *f = new barname::CFoo();
delete f;
}
#ifndef con001_CFoo_h
#define con001_CFoo_h
namespace barname {
class CFoo
{
public:
CFoo();
~CFoo();
static void fooMethod();
};
inline CFoo::CFoo()
{
}
inline CFoo::~CFoo()
{
}
}
#endif
in other file
#include "CFoo.h"
namespace barname
{
void CFoo::fooMethod()
{
}
}
compiled ok in XCode 4.6
I've got a third party library named person.lib and its header person.h. This is my actual project structure and it compiles and runs perfectly.
Actual Structure:
main.cpp
#include <iostream>
#include <time.h>
#include <ctype.h>
#include <string>
#include "person.h"
using namespace person;
using namespace std;
class Client : public Person
{
public:
Client();
void onMessage(const char * const);
private:
void gen_random(char*, const int);
};
Client::Client() {
char str[11];
gen_random(str, 10);
this->setName(str);
}
void Client::onMessage(const char * const message) throw(Exception &)
{
cout << message << endl;
}
void Client::gen_random(char *s, const int len) {
//THIS FUNCTION GENERATES A RANDOM NAME WITH SPECIFIED LENGTH FOR THE CLIENT
}
int main()
{
try
{
Person *p = new Client;
p->sayHello();
}
catch(Exception &e)
{
cout << e.what() << endl;
return 1;
}
return 0;
}
I want to refactor my code by dividing the declaration of my Client class from its definition and create client.h and client.cpp. PAY ATTENTION: sayHello() and onMessage(const * char const) are functions of the person library.
Refactored Structure:
main.cpp
#include <iostream>
#include "client.h"
using namespace person;
using namespace std;
int main()
{
try
{
Person *p = new Client;
p->sayHello();
}
catch(Exception &e)
{
cout << e.what() << endl;
return 1;
}
return 0;
}
client.cpp
#include "client.h"
using namespace person;
using namespace std;
Client::Client() {
char str[11];
gen_random(str, 10);
this->setName(str);
}
void Client::onMessage(const char * const message) throw(Exception &)
{
cout << message << endl;
}
void Client::gen_random(char *s, const int len) {
//THIS FUNCTION GENERATES A RANDOM NAME WITH SPECIFIED LENGTH FOR THE CLIENT
}
client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <time.h>
#include <ctype.h>
#include <string>
#include "person.h"
class Client : public Person
{
public:
Client();
void onMessage(const char * const);
private:
void gen_random(char*, const int);
};
#endif
As you can see, I've simply created a client.h in which there's the inclusion of the base class person.h, then I've created client.cpp in which there's the inclusion of client.h and the definitions of its functions. Now, the compilation gives me these errors:
error C2504: 'Person': base class undefined client.h 7 1 Test
error C2440: 'inizialization': unable to convert from 'Client *' to 'person::impl::Person *' main.cpp 15 1 Test
error C2504: 'Person': base class undefined client.h 7 1 Test
error C2039: 'setName': is not a member of 'Client' client.cpp 8 1 Test
error C3861: 'sendMessage': identifier not found client.cpp 34 1 Test
It's a merely cut© refactoring but it doesn't work and I really don't understand WHY! What's the solution and why it gives me these errors? Is there something about C++ structure that I'm missing?
Here's a dog-n-bird implementation (ruff ruff, cheep cheep)
cLawyer is defined and implemented in main.cpp, while cPerson and cClient are defined in their own header files, implemented in their own cpp file.
A better approach would store the name of the class. Then, one wouldn't need to overload the speak method - one could simply set the className in each derived copy. But that would have provided in my estimates, a less useful example for you.
main.cpp
#include <cstdio>
#include "cClient.h"
class cLawyer : public cPerson
{
public:
cLawyer() : cPerson() {}
~cLawyer() {}
void talk(char *sayWhat){printf("cLawyer says: '%s'\n", sayWhat);}
};
int main()
{
cPerson newPerson;
cClient newClient;
cLawyer newLawyer;
newPerson.talk("Hello world!");
newClient.talk("Hello world!");
newLawyer.talk("Hello $$$");
return 0;
}
cPerson.h
#ifndef cPerson_h_
#define cPerson_h_
class cPerson
{
public:
cPerson();
virtual ~cPerson();
virtual void talk(char *sayWhat);
protected:
private:
};
#endif // cPerson_h_
cPerson.cpp
#include "cPerson.h"
#include <cstdio>
cPerson::cPerson()
{
//ctor
}
cPerson::~cPerson()
{
//dtor
}
void cPerson::talk(char *sayWhat)
{
printf("cPerson says: '%s'\n",sayWhat);
}
cClient.h
#ifndef cClient_h_
#define cClient_h_
#include "cPerson.h"
class cClient : public cPerson
{
public:
cClient();
virtual ~cClient();
void talk(char *sayWhat);
protected:
private:
};
#endif // cClient_h_
cClient.cpp
#include "cClient.h"
#include <cstdio>
cClient::cClient()
{
//ctor
}
cClient::~cClient()
{
//dtor
}
Output
cPerson says: 'Hello world!'
cClient says: 'Hello world!'
cLawyer says: 'Hello $$$'
Suggestions noted above:
//In the cPerson class, a var
char *m_className;
//In the cPerson::cPerson constructer, set the var
m_className = "cPerson";
//Re-jig the cPerson::speak method
void cPerson::speak(char *sayWhat)
{
printf("%s says: '%s'\n", m_className, sayWhat);
}
// EDIT: *** remove the speak methods from the cClient and cLawyer classes ***
//Initialize the clas name apporpriately in derived classes
//cClient::cClient
m_className = "cClient";
//Initialize the clas name apporpriately in derived classes
//cLaywer::cLaywer
m_className = "cLawyer";
You are declaring the class Client twice - once in the .h file and once in .cpp. You only need to declare it in the .h file.
You also need to put the using namespace person; to the .h file.
If class Person is in namcespace person, use the person::Person to access it.
The client.cpp must contain definitions only!
I think for the linker the class Client defined in client.h and class Client defined in client.cpp are different classes, thus it cannot find the implementation of Client::Client(). I purpose to remove the declaration of class Client from the client.cpp and leave there only definitions of functions:
// client.cpp
#include <time.h>
#include <ctype.h>
#include <string>
#include "client.h"
using namespace std;
Client::Client()
{
//DO STUFF
}
void Client::onMessage(const char * const message)
{
//DO STUFF
}
void Client::gen_random(char *s, const int len) {
//DO STUFF
}