无法实例化抽象类 - 如何解决此问题才能正常工作?

时间:2014-07-23 08:38:34

标签: c++ visual-studio-2012 abstract-class instantiation

我试图创建二进制搜索树数据库,在那里我可以搜索字典条目。我试图弄清楚如何在我的代码中解决这个问题,我得到了一个必备的基类,它也是一个模板抽象类,它用于派生BST或BinarySearchTree类,但是我&#39 ;我在Visual Studio 2012中编译时遇到问题,它一直在说我的功能 (例如,int.SearchableADT :: loadFromFile(std :: string)是抽象的;)

此外,这个构造函数看起来是否正确?我只是想让构造函数将头设置为NULL,但我不知道是否需要在构造函数中的某处使用SearchableADT。

感谢您的帮助!!我需要它!

#include <cstring>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;

template <typename T>
class SearchableADT
{
public:
    virtual int loadFromFile(string filename)= 0;
    //virtual void clear(void) = 0;
    virtual void insertEntry(T value) = 0;
    virtual void deleteEntry(T value) = 0;
    virtual bool isThere(T value) = 0;
    virtual int numEntries(void) = 0;
};

template <typename T>
class BST : public SearchableADT<T>
{
public:
    BST():SearchableADT<T> {head = NULL;} //default constructor
    virtual int loadFromFile(string filename);
    //virtual void clear(void);
    virtual void insertEntry(T value);
    virtual void deleteEntry(T value);
    virtual bool isThere(T value);
    virtual int numEntries(void);
 private:
    struct t_node
    {
        string data;
        t_node* L; //left node
        t_node* R; //right node
    };
    t_node* head; // head of the whole BST
    t_node* cPTR; // current pointer
    t_node* pPTR; // parent pointer
    t_node* tPTR; //temporary pointer

};
template <typename T>
bool BST<T>::isThere(T value)
{
    bool found = false;

if(head == NULL)
{
    cout<<"Error: No data found in ADT\n";
    return found;
}

cPTR = head;
//loops through the tree until the entry is found
while(cPTR != NULL)
{
    if(cPTR->data == info)
    {
        found = true;
        break;
    }

    else
    {
        pPTR = cPTR;
        if(info > cPTR->data)
            cPTR = cPTR->R;
        else
            cPTR = cPTR->L;
    }
}
if(!found)
{
    cout<<"'"<<info<<"' was not found in the dictionary\n";
}
return found;
}//end of isThere() function

template <typename T2>
void BST<T2>::insertEntry(T2 info)
{
    t_node* t = new t_node;
    t->data = info;
    t->L    = NULL;
    t->R    = NULL;
    pPTR    = NULL;
    if(head->data == NULL)
        head = t;
    else
    {
        t_node* cPTR; //current pointer
        cPTR = head;

        //checks to see if the data just entered is
        //greater than the head 
        while(cPTR)
        {
            pPTR = cPTR;
            if( t->data > cPTR->data)
                cPTR = cPTR->R;
            else
                cPTR = cPTR->L;
        }

        //checks to see if the data just entered is
        // less than the parent data that was 
        // set equal to cPTR;
        if(t->data < pPTR->data)
        {
            pPTR->L = t;

        }
    else
    {
        pPTR->R = t;
    }
}
}//end of insertEntry() function

template <typename T2>

void BST<T2>::deleteEntry(T2 info)
{
    //i use this as an example of abstraction
    //after using this function the cPTR and pPTR are already pointing to the data needed to be found
    if(!isThere(info))
    {
        cout<<"The data: '"<<info<<"' could not be found in the ADT, sorry!\n";
        return;
    }

    //one has to account for all possibilities when deleting data
    //1.) - Removing just a leaf node (no children) **easy  
//2.) - Removing a leaf node with 1 child **medium
//3.) - Removing a leaf node with 2 children **hard

//case 1
if( cPTR->L == NULL && cPTR ->right == NULL)
{
    if(pPTR-> L == cPTR)
        pPTR->L = NULL;
    else
        pPTR->R = NULL;
    delete cPTR;
    return;
}//end of case 1

//case 2
else if((cPTR->L == NULL && cPTR->R != NULL) ||
   (cPTR->L != NULL && cPTR->R == NULL))
{
    //if the left data of cptr has data and the right data is NULL
    if(cPTR->L != NULL && cPTR->R == NULL)
    {
        if(pPTR->L == cPTR)
        {
            pPTR->L = cPTR->right;
            delete cPTR;
        }
        else
        {
            pPTR->R = cPTR->L;
            delete cPTR;
        }
    }

    else //right child present, and left child is NULL 
    {
        if(pPTR->L == cPTR)
        {
            pPTR->L = cPTR->right;
            delete cPTR;
        }
        else
        {
            pPTR->R = cPTR->R;
            delete cPTR;
        }
    }

    //case 3
    else if((cPTR->L != NULL && cPTR->R != NULL))
    {
        tPTR=cPTR->R;

        //if the right node doesn't have a right leaf or left leaf, delete that node
        if((tPTR->L == NULL && tPTR->R == NULL))
        {
            cPTR = tPTR;
            delete cPTR;
            cPTR->R = NULL;
        }
        else
        {
            if(tPTR->L != NULL)
            {
                t_node* secPTR;
                secPTR = tPTR->L;
                //cycle through left nodes until you find the lowest left node
                while(secPTR->L != NULL)
                {
                    secPTR = secPTR->L;
                }
                //because you're only setting the data equal to eachother the cPTR keeps its left and right nodes
                //therefore it correctly replaces the data without unwanted loss of other information
                cPTR->data = secPTR->data;
                delete secPTR;
                cPTR->L    = NULL;
            }
            else
            {
                cPTR->data = tPTR->data;
                cPTR->R    = tPTR->R;
                delete tPTR;
            }

        }
    }
}
}  //end of deleteEntry() function

template <typename T2>
int BST<T2>::numEntries()
{
    int num = 0;

    if(head->R == NULL && head-> L == NULL)
    {
        num++;
    }
    else
    {
        //note i learned that you could count the nodes like this via the web
        //i could redo this with recursion if you'd like
        num = count(head->L) + count (head->R) + 1;
    }
    return num;
}
template <typename T2>
int BST<T2>::loadFromFile(string filename)
{
    int count = 0;
    string tempdata;
    ifstream fin(filename);
    if(!fin)
    {
        cout<< "Error: Could no open file\n";
        count--;
    }
    while(fin)
    {
        fin>>tempdata;
        if(fin)
        {
            insertEntry(tempdata);
            count++;
        }
    }
    fin.close();
    return count;       
 }//end of loadFromFile() function


int main()
{
    char choice 'z';
    string tempdata,
           fileloc;

cout<<"Welcome to Jordin Ray's Spell Check Application\n"
    <<"Please pick a tree type\n"
    <<"'b' -Binary Search Tree\n"
    <<"'a' -AVL tree\n"
    <<"'h' -hash table\n";
cin>>choice;
cout<<"Please give the exact location of the file for download\n";
cin>>fileloc;
if(choice == 'b')
{
    SearchableADT<string> dictionary = new BST<string>;
    dictionary.loadFromFile(fileloc);
    char ch = 'z';
    while(ch != 'q')
    {
        string word = "";
        if(ch == 'e')
        {
            cout<<"Please enter the word you would like to search for\n";
            cin>>word;
            dictionary.isThere(word);
        }
        else if (ch == 'p')
        {
            cout<<"Please enter the partial word you would like to look for with a '?' where the missing letter is: \n"
                <<"Ex. - '?nd' will search for words in the dictionary that have those last two letters\n";
            //dictionary.partialIsThere(word);
        }
        else if (ch == 'c')
        {
            dictionary.clear();
        }
        else if (ch == 's')
        {
            int entries;
            entries = dictionary.numEntries();
            cout<<"\nThe amount of entries logged in the database is: "<<entries<<".\n";
        }
        cout<<"Would you like to:\n"
            <<"Clear the dictionary      - 'c'\n"
            <<"Check for an entry        - 'e'\n"
            <<"Check for a partial entry - 'p'\n"
            <<"Report Statistics         - 's'\n"
            <<"Quit                      - 'q'";
        cin>>ch;
    }//end of while loop
}
return 0;
}//end of main

1 个答案:

答案 0 :(得分:1)

我尝试在Mac上用Clang ++编译你的代码,你的问题比模板/继承混合更早开始。即在第23行:

error: expected '('
    BST():SearchableADT<T> {head = NULL;} //default constructor

(解决方案:基础构造函数需要参数列表,添加()

并且,在修复了第59行的下一个之后:

error: use of undeclared identifier 'info'
    if(cPTR->data == info)

我在这个阶段放弃了。还有一些其他小问题,例如在C ++中没有必要#include <cstring>:对于所有期望C风格字符串的函数,你总是可以使用c_str() std::string方法。还应观察到const正确性:例如loadFromFile(string filename)应该看起来像loadFromFile(const string& filename)。等

现在到了主要问题。我不明白为什么你需要那个模板化的基类。如果您可以避免使用模板并且只编写一个存储字符串的类,那么整个设计会更容易。

BTW完全有可能有一个抽象的模板基类,从中派生出具体的模板类。只需确保为所有纯虚方法提供具体实现。这是一个可以帮助您入门的组合示例:

#include <string>
#include <iostream>

template<typename T>
class AbstractBase {
    public:

    virtual const T& func() const = 0;

};

template<typename T>
class Derived: public AbstractBase<T> {
    public:

    // stores x
    Derived(const T& x): AbstractBase<T>(), _x(x) {}

    // returns x
    const T& func() const { return _x; }

    private:
    T _x;
};

int main(int argc, char *argv[]) {
    Derived<std::string> d("foo");
    std::cout << d.func() << std::endl;
    return 0;
}

然而,模板/继承混合设计问题将在以后某些待实现的方法对某些模板参数没有意义的情况下使其丑陋的头部。上面的例子是“便宜的”,因为func()只返回一个值。如果我添加一个返回twice()的函数2 * _x怎么办?如果_x是一个数字,那很好,但字符串呢?还是矢量?你明白了......: - )