0

So I have a base class called RequestChannel and I have another class that is derived from it called FIFORequestChannel. I also have a file called trial.cpp where I have my main. I therefore have following files:

RequestChannel.h
FIFORequestChannel.h (includes RequestChannel.h)
FIFORequestChannel.cpp (includes FIFORequestChannel.h)
trial.cpp (includes FIFORequestChannel.h)

I didn't see the point of having .cpp file for RequestChannel since it is just my base class and no implementation is provided. I have made the following makefile to compile it:

all: trial

FIFORequestChannel.o: FIFORequestChannel.h RequestChannel.h FIFORequestChannel.cpp
    g++ -g -w -Wall -O1 -std=c++11 -c FIFORequestChannel.cpp 

trial: trial.cpp FIFORequestChannel.o  
    g++ -g -w -Wall -O1 -std=c++11 -o trial trial.cpp FIFORequestChannel.o -lpthread

clean:
    rm -rf *.o  trial

My problem is that I am trying to create a makefile for it but I keep getting the following error:

Undefined symbols for architecture x86_64:
  "typeinfo for RequestChannel", referenced from:
      typeinfo for FIFORequestChannel in FIFORequestChannel.o
  "vtable for RequestChannel", referenced from:
      RequestChannel::RequestChannel() in FIFORequestChannel.o
      RequestChannel::~RequestChannel() in FIFORequestChannel.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [trial] Error 1

I don't know if I am also supposed to include RequestChannel.h in FIFOFIFORequestChannel.cpp even though it is already included in FIFOFIFORequestChannel.h already Here is the code:

RequestChannel.h

class RequestChannel {
public:
 RequestChannel(){};
 ~RequestChannel(){};
 virtual int cwrite (string)= 0;
 virtual string cread ();
};

FIFORequestChannel.h

#include "RequestChannel.h"
using namespace std;

class FIFORequestChannel: public RequestChannel {
private:

public:
   FIFORequestChannel();
  ~FIFORequestChannel();
   int cwrite (string);
   string cread();
};

FIFORequestChannel.cpp

#include "FIFORequestChannel.h"

using namespace std;

FIFORequestChannel::FIFORequestChannel(){
    cout << "Constructor worked" <<endl;
}

FIFORequestChannel::~FIFORequestChannel(){
    cout << "Destructor worked" <<endl;
}

int FIFORequestChannel::cwrite (string){
    cout << "cwrite() inside of derived class" << endl;
}
string FIFORequestChannel::cread(){
    cout << "cread() inside of derived class" << endl;
}

trial.cpp

#include <iostream>
#include "FIFORequestChannel.h"
using namespace std;

int main(){
    RequestChannel* rq = new FIFORequestChannel();
    return 0;
}
Pape Sow Traore
  • 179
  • 1
  • 3
  • 14
  • 2
    This has nothing to do with `make`. You'd get the same error running the build commands manually. – melpomene Nov 17 '18 at 21:15
  • 2
    "*... no implementation is provided*" is probably the source of your problems, but it's hard to say without a [mcve]. – melpomene Nov 17 '18 at 21:16
  • 1
    Yep, `RequestChannel();` is declared but not implemented anywhere. Exactly what the linker is complaining about. – melpomene Nov 17 '18 at 21:23

2 Answers2

2

Your problem has nothing to do with make.

The issue is that

class RequestChannel {
public:
    RequestChannel();
    ~RequestChannel();
};

declares two functions (the constructor and destructor of RequestChannel), but they're not implemented anywhere.

The easiest solution in your case might be to simply leave the class empty:

class RequestChannel {};
melpomene
  • 84,125
  • 8
  • 85
  • 148
  • So what would I have to do if I had to override some functions – Pape Sow Traore Nov 17 '18 at 21:29
  • @PapeSowTraore You mean custom code in the constructor/destructor? You'd have to define those functions somewhere, either inline (`class RequestChannel { public: RequestChannel() { ... } ~RequestChannel() { ... } };`) or in a corresponding .cpp file. – melpomene Nov 17 '18 at 21:31
  • And would I need to make the RequestChannel constructor and destructor virtual as well if I want to overwrite them in the derived class of FIFORequestChannel – Pape Sow Traore Nov 17 '18 at 21:46
  • @Pape Sow Traore yes , but given the simplicity of the class (just constructor and destructor) there isn't a need for it at all as every class has a constructor and destructor provided by the compiler if a default constructor and destructor are not written. Is there a specific design pattern you are trying to achieve here? – johnathan Nov 17 '18 at 21:50
  • 1
    @PapeSowTraore Constructors can't be virtual. Destructors need to be virtual if you want to be able to `delete` objects through a base pointer (e.g. `delete rq` where `rq` was declared as `RequestChannel *`). – melpomene Nov 17 '18 at 21:52
  • I have updated what I have and the error I am getting. Hopefully this helps you see what I am trying to do as a whole. I have implemented both the destructor and constructor in the base class – Pape Sow Traore Nov 17 '18 at 21:58
1
  1. This is not a problem of make
  2. The linker complains about missing implementation of RequestChannel() and ~RequestChannel()
  3. There is more to know about derivation from a base class:
    • Prevention of memory leak: see question about virtual destructor: if you call delete on a base class pointer (RequestChannel*), which points to an object of type FIFORequestChannel, then the destructor of RequestChannel is called instead of the one of FIFORequestChannel. This is usually not that what is expected nor what is needed. That's a very common reason for a memory leak, especially for C++ Newcomer. Declare your base class and subclass destructors virtual to avoid that.
    • Prevention of instantiation of abstract class (interface) by making the destructor pure virtual: RequestChannel seems to be an abstract base class, which is not supposed to be instantiated. The instantiation is disallowed by declaring a pure virtual destructor virtual ~RequestChannel()=0;. Anyway, you need to provide an implementation of the pure virtual destructor according to the question about pure virtual destructor. Usually, pure virtual functions are not defined in the same class.
  4. Move definition of destructor into RequestChannel.cpp, because otherwise you may get multiple definitions, if you include RequestChannel.h elsewhere. Alternatively it can be defined as inline, but I never tried it, if it works as intended.

That's why I would recommend to do it like this:

//RequestChannel.h

class RequestChannel
{
public:
    virtual ~RequestChannel()=0; //virtual: to call derived destructor
                                 //=0: pure virtual, making the class abstract
};

//RequestChannel.cpp

RequestChannel::~RequestChannel() {}
tangoal
  • 724
  • 1
  • 9
  • 28
  • Quick question, how can I make the following line: virtual string cread() is giving the following error "Illegal Instruction 4". Do I need to add "=0" even though that function returns a string? – Pape Sow Traore Nov 17 '18 at 22:36
  • I cannot say if this is the reason. You can try. Furthermore: please specify the name of the `string` argument of `cwrite`: `virtual cwrite (string s)=0;`. Also in the derived class and the cpp. – tangoal Nov 17 '18 at 22:55