Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly extend a class in C++ and writing its header file?

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&copy 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?

like image 311
Angelo Avatar asked Sep 29 '13 15:09

Angelo


2 Answers

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";
like image 43
enhzflep Avatar answered Sep 24 '22 21:09

enhzflep


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
}
like image 71
Shimon Rachlenko Avatar answered Sep 24 '22 21:09

Shimon Rachlenko