-1

My question is that, I have a template class template<class T> AList as base, and I wanna get a derived class from the template, i.e. get class BList: public AList<mydefinedtype> without much modification.

alist.h

#ifndef alist_h
#define alist_h

template<class T> class AList
{
public:
    AList(){
        arr = new T[20];
        numitems = 0;
    };
    void append(T value);
       
private:
    T *arr;
    int numitems;
};


#endif /* alist_h */

alist.cpp

#include "alist.h"
template<class T> void AList<T>::append(T value)
{
    arr[numitems] = value;
    ++numitems;
    return;
}

blist.h

#include "alist.cpp"
#include <string>
using namespace std;

typedef struct 
{
    string a, b;
    int key;
} record;

class BList: public AList<record>{
    public:
        void test(void){
            cout << "this is from BList" << endl;
        }
};

blist.cpp

#include "blist.h"

main.cpp

#include <iostream>
#include "blist.cpp"

using namespace std;


int main(){
    record testRecord[3];
    testRecord[0] = {"Mark", "A", 1};
    testRecord[1] = {"Anla", "B", 2};
    testRecord[2] = {"Cindy", "C", 3};

    BList blist = BList();
    for(auto i: testRecord){
        // blist.append(i); // will compile error
        blist.test();
    } 
    return 0;
}

It will fail as follows, I wonder how to compile or how to fix the bug. error info

Undefined symbols for architecture x86_64:
  "AList<record>::append(s)", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64

Not sure where comes from the issue.

Q Jiang
  • 1
  • 1
  • 2
    Please provide a [mcve] and the exact error message. – Werner Henze Jan 17 '21 at 14:30
  • 5
    My crystal ball suspects that you should read [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa) – molbdnilo Jan 17 '21 at 14:33
  • @WernerHenze I just add some more details – Q Jiang Jan 17 '21 at 14:42
  • Did you read [mcve]? I don't see a [mcve] that I can copy and test. – Werner Henze Jan 17 '21 at 14:46
  • 1
    You have provided a *declaration* for `append`. You need to actually *define* append, i.e., you must provide a function body with an implementation. The compile error `Undefined symbol "AList::append(s)" is telling you it can't find append's implementation. – Perette Jan 17 '21 at 15:00
  • @WernerHenze Sorry, this is my first post. I just post all details. Hope it is enough for the problem. – Q Jiang Jan 17 '21 at 15:12
  • 1
    Does this answer your question? [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – Andrey Semashev Jan 17 '21 at 15:12
  • @Perette I did provide a definition in other cpp file, I am not sure if I compile all the files correctly. – Q Jiang Jan 17 '21 at 15:13
  • @AndreySemashev I did read it briefly, but not quite catch the point why it did not work for my case. – Q Jiang Jan 17 '21 at 15:24
  • The `AList::append` method is not instantiated if it is not ODR-used in the same translation unit where it is defined. It is not used in your `alist.cpp`, so it is not instantiated and therefore missing when linking. – Andrey Semashev Jan 17 '21 at 15:27
  • Your point is much impressive for me. I am not so familiar with cpp, so I wonder why it is the case. From some of my experiences, when I define a class but not use in a cpp file, it will work when linking in the end, what is the difference here? Or could you give some advice to fix it, then I may get more ideas. – Q Jiang Jan 17 '21 at 15:34

2 Answers2

0
// Example program
    #include <iostream>
    #include <string>
    
    struct record{
        int a;
    };
    
    template<class T> 
    class AList{
    public:
        AList()=default;
        void append(T value){}
    };
    
    template<class T>
    class BList:public AList<T>{
    public:
        void test(void){}
    };
    
    
    int main()
    {
        BList<record> blist;
        
    record recordarr[3] ;
    // some initialization 
    
    for(auto i:recordarr){
        blist.append(i); 
        blist.test(); 
    }
    }

The problem you have is that the AList() constructor, append(T) and test() are only declared but not defined. The above code should compile.

jiadong
  • 135
  • 7
0

You should put your template classes entirely in header files. See this question and this C++ FAQ for details on why.

You should also never #include .cpp files. You should only ever #include header files.

Below I have your code after the required modifications to make it compile. I also removed your memory leak.

alist.h:

#ifndef alist_h
#define alist_h

template<class T> class AList {
public:
    AList() {
        arr = new T[20];
        numitems = 0;
    };

    ~AList() {
        delete[] arr;
    }

    void append(T value) {
        arr[numitems] = value;
        ++numitems;
    }

private:
    T *arr;
    int numitems;
};

#endif /* alist_h */

blist.h:

#ifndef blist_h
#define blist_h

#include "alist.h"
#include <string>
using namespace std;

typedef struct {
    string a, b;
    int key;
} record;

class BList: public AList<record> {
public:
    void test(void) {
        cout << "this is from BList" << endl;
    }
};

#endif /* blist_h */

main.cpp:

#include <iostream>
#include "blist.h"

using namespace std;

int main() {
    record testRecord[3];
    testRecord[0] = {"Mark", "A", 1};
    testRecord[1] = {"Anla", "B", 2};
    testRecord[2] = {"Cindy", "C", 3};

    BList blist = BList();
    for (auto i: testRecord) {
        blist.append(i);
        blist.test();
    }
    return 0;
}

Summary of changes

I made the following changes:

  • Moved body of AList::append into alist.h, and deleted alist.cpp
  • Added AList destructor to free the dynamically allocated memory allocated in AList::AList
  • In blist.h, included alist.h instead of alist.cpp
  • Deleted blist.cpp
  • In main.cpp, included blist.h instead of blist.cpp
Shane Bishop
  • 3,905
  • 4
  • 17
  • 47