用用户定义的类型替换基本类型将导致嵌套类中未指定的标识符/不完整类型错误

时间:2016-05-28 18:43:59

标签: c++ linked-list inner-classes incomplete-type

我需要构建一个服装项目(Line)的双向链表(LinkedList)。我们的想法是提供类似于列表的功能。每个类都可以自己工作,但是当我尝试将“数据”成员变量的数据类型从LinkedList中的字符串更改为Line时,所有地狱都会破坏,我主要得到关于“数据”的错误:未定义类,未定义类型,不完整类型等...

我很感激任何帮助,因为我的头已经开始受伤了!

int main() {
    string node1{ "1" };
    string node2{ "2" };
    string node3{ "3" };

     LinkedList list;

     cout << "Is Empty? " << list.empty() << endl;
     cout << "Size " << list.size();

     list.push_front(node3);
     list.push_front(node2);
     list.push_front(node1);

     cout << "Is Empty? " << list.empty() << endl;
     cout << "Size " << list.size() << "\n\n";

     for (int i{ 1 }; i <= list.size(); ++i) {
    list.print(i);
     }
    cout << endl;

    return 0;
}
#ifndef LINKEDLIST_H
#define LINKEDLIST_H

#include "Line.h"
#include <string>

using T = std::string;

class LinkedList
{
public:
    LinkedList() : theSize{ NULL }, head{ nullptr }, tail{ nullptr } {};    // default ctor

    virtual ~LinkedList();                              // dtor
    LinkedList(const LinkedList&);                      // copy-ctor
    const LinkedList& operator=(const LinkedList&);     // copy assignment operator

    void push_front(const T&);              // insert node at front of list
    void push_back(const T&);               // insert node at back of list
    void pop_front();                       // remove the first node from front of the list
    void pop_back();                        // remove the last node from the end of the list

    void insert(const T&, int);         // insert a new node with T at position k in the list
    void remove(int);                   // remove node at position k in the list

    int size() const;                   // returns the size of this list
    bool empty() const;                     // returns whether this list is empty
    void print(int) const;              // print the contents at position
private:
    class ListNode {
    public:
    ListNode() : nextPtr{ nullptr }, prevPtr{ nullptr } {};                 // default ctor
    explicit ListNode(const T&, ListNode* = nullptr, ListNode* = nullptr);  // ctor

    ~ListNode() = default;                              // dtor

    const T& get_data() const {                         // get data in node
        return data;
    }
    ListNode* get_nextPtr() const {                     // get the pointer to the next node
        return nextPtr;
    }
    ListNode* get_prevPtr() const {                     // get the pointer to previous node
        return prevPtr;
    }

    void set_data(const T& data) {          // set data in node
        this->data = data;
    }
    void set_nextPtr(ListNode* nextPtr) {   // set the next pointer in node
        this->nextPtr = nextPtr;
    }
    void set_prevPtr(ListNode* prevPtr) {   // set the previous pointer in node
        this->prevPtr = prevPtr;
    }
    private:
        T data;                             // node data member
        ListNode* nextPtr;                      // pointer to the next node
        ListNode* prevPtr;                      // pointer to the previous node
    };

    int theSize;
    ListNode* head;
    ListNode* tail;

    // utility function to allocate new node
    ListNode* getNewNode(const T& data) {
        return new ListNode{ data };
    }

    // utility function to deallocate list
    void clear();

    // utility function to copy list contents
    void copy(const LinkedList& rhs);
};

#endif
#include "stdafx.h"
#include "LinkedList.h"
#include <string>
#include <iostream>

using std::cout;
using std::endl;


// virtual dtor for LinkedList class 
LinkedList::~LinkedList() {
    this->clear();
}


// copy-ctor
LinkedList::LinkedList(const LinkedList& rhs) {
    this->copy(rhs);
}


// copy assignment operator
const LinkedList& LinkedList::operator=(const LinkedList& rhs) {    
if (&rhs != this) {     // avoid self-assignment
    this->clear();      // release space
    this->copy(rhs);    // copy contents of rhs into new object
}

// enable cascading calls such as x = y = z
return *this;
}


// insert node at front of list
void LinkedList::push_front(const T& data) {
ListNode* newPtr{ getNewNode(data) };   // new node

if (empty()) {                          // list is empty
    head = tail = newPtr;               // both head and tail point to the only existing node
}
else {
    head->set_prevPtr(newPtr);          // aim the previous pointer of the old head node at the new head node
    newPtr->set_nextPtr(head);          // aim new head node to old head node
    head = newPtr;                      // aim head at the new node
}

++theSize;                              // increment the size of list
}


// insert node at back of list
void LinkedList::push_back(const T& data) {
    ListNode* newPtr{ getNewNode(data) };   // new node

if (empty()) {                          // list is empty
    head = tail = newPtr;               // both head and tail point to the only existing node
}
else {
    tail->set_nextPtr(newPtr);          // aim next pointer of the old tail node to the new tail node
    newPtr->set_prevPtr(tail);          // aim previous pointer of new tail node to the old tail node 
    tail = newPtr;                      // aim tail at the new tail node
}

++theSize;                              // increment the size of list
}


// remove the first node from front of the list
void LinkedList::pop_front() {
if (empty()) {                              // list is empty
    cout << "List is empty, unable to remove from an empty list!\n";
}
else {
    ListNode* tempPtr{ head };              // hold item to delete

    if (head == tail) {                     // at most one node in list
        head = tail = nullptr;              // no nodes remain after removal
    }
    else {
        head = head->get_nextPtr();         // set the head to point to the previous second node
        head->set_prevPtr(nullptr);         // the previous pointer of head must be nullptr
    }

    delete tempPtr;                         // delete the old first item
    tempPtr = nullptr;

    --theSize;                              // decrement the size of list
}
}


// remove the last node from the end of the list
void LinkedList::pop_back() {
if (empty()) {                                          // list is empty
    cout << "List is empty, unable to remove from an empty list!\n";
}
else {
    ListNode* tempPtr{ tail };                          // hold item to delete

    if (head == tail) {                                 // at most one node in list
        head = tail = nullptr;                          // no nodes remain after removal
    }
    else {
        ListNode* currentPtr{ head };

        while (currentPtr->get_nextPtr() != tail) {
            currentPtr = currentPtr->get_nextPtr();
        }

        tail = currentPtr;
        currentPtr->set_nextPtr(nullptr);               // the nextPtr of the tail must be null
    }

    delete tempPtr;                                     // delete the old last item
    tempPtr = nullptr;

    --theSize;                                          // decrement the size of list
}
}


// insert a new node at position k in the list
void LinkedList::insert(const T& data, int position) {
    if (position == 1) {
        push_front(data);                                   // if position is one, use the push_front function to add node to the front of the list
}
else if (position > 1 && position <= theSize) {
    ListNode* newPtr{ getNewNode(data) };   
    ListNode* currentPtr{ head };

    for (int i { 1 }; i <= position - 1; ++i) {
        currentPtr = currentPtr->get_nextPtr();         // traverse the list until location at (position - 1)
    }

    newPtr->set_prevPtr(currentPtr->get_prevPtr());     // aim the prevPtr of newPtr to node at current location at (position - 1) 
    newPtr->set_nextPtr(currentPtr);                    // aim the nextPtr of newPtr to node at old location at position 
    currentPtr->get_prevPtr()->set_nextPtr(newPtr);     // aim the nextPtr of node at location (position - 1) at new node newPtr
    currentPtr->set_prevPtr(newPtr);                    // aim the prevPtr of the node at old location at position at point at the new node newPtr 

    ++theSize;                                          // increment the size of list

}
else {
    cout << "Position is out of bounds. Position must be in [" << 1 << "," << theSize << "].\n";
}   
}


// remove node at position k in the list
void LinkedList::remove(int position) {
if (position == 1) {
    pop_front();                                                    // if position is one, use the pop_front function to remove node from the front of the list
}
else if (position == theSize) {
    pop_back();                                                     // if position is at the end of the list, use the pop_back function to remove node from the back of the list
}
else if (position > 1 && position < theSize) {
    ListNode* tempPtr{ head };

    for (int i{ 1 }; i < position; ++i) {
        tempPtr = tempPtr->get_nextPtr();                           // traverse the list until location at position 
    }
    tempPtr->get_prevPtr()->set_nextPtr(tempPtr->get_nextPtr());    // aim the nextPtr of node at old location at (position - 1) to node at old location (position + 1)
    tempPtr->get_nextPtr()->set_prevPtr(tempPtr->get_prevPtr());    // aim the prevPtr of node at old location at (position + 1) to node at old location (position - 1)

    delete tempPtr;                                                 // remove node and free space
    tempPtr = nullptr;

    --theSize;                                                      // decrement the size of list
}
else {
    cout << "Position is out of bounds. Position must be in [" << 1 << "," << theSize << "].\n";
}
}

// returns the size of this list
int LinkedList::size() const {
return theSize;
}


// returns whether this list is empty
bool LinkedList::empty() const {
return theSize == 0;                                                
}


// prints contents of the list at location at position
void LinkedList::print(int position) const {
if (!empty()) {
    if (position >= 1 && position <= theSize) {
        ListNode* tempPtr{ head };

        for (int i{ 1 };  i <= position - 1; ++i) {
            tempPtr = tempPtr->get_nextPtr();                   // traverse the list until location at position 
        }

        cout << tempPtr->get_data() << endl;
    }
    else {
        cout << "Position is out of bounds. Position must be in [" << 1 << "," << theSize << "].\n";
    }
}
}


// utility function to deallocate list
void LinkedList::clear() {
if (!empty()) {                                                 // list is not empty
    ListNode* currentPtr{ head };
    ListNode* tempPtr{ nullptr };

    while (currentPtr != nullptr) {                             // traverse the list and delete remaining nodes
        tempPtr = currentPtr;
        currentPtr = currentPtr->get_nextPtr();
        delete tempPtr;
        --theSize;
    }
    head = tail = nullptr;
}
}


// utility function to copy list contents
void LinkedList::copy(const LinkedList& rhs) {
ListNode* tempPtr{ rhs.head };

// traverse the list and insert data in node at each corresponding position
while (tempPtr != nullptr) {
    push_back(tempPtr->get_data());
    tempPtr = tempPtr->get_nextPtr();
}
}


// ctor for ListNode class
LinkedList::ListNode::ListNode(const T& data, ListNode* prevPtr, ListNode* nextPtr) {
    set_data(data);
    set_nextPtr(nextPtr);
    set_prevPtr(prevPtr);
}
#pragma once
#include <iostream>

class Line
{
public:
Line() : linePtr{ new char {NULL} }, lineLength{ 1 }, lineCapacity{ 0 } {};     // default ctor
Line(const char*);                                                              // ctor: construct this line from a given C-string
Line(char);                                                                     // ctor: construct this line from a given character

virtual ~Line();                            // virtual dtor
Line(const Line&);                          // copy-ctor
const Line& operator=(const Line&);         // copy-assignment operator

const char* cstr() const;                   // return C-style version of this line
int length() const;                         // return length of this line
int capacity() const;                       // return capacity of this line
void resize();                              // double capacity if this line is full
bool empty() const;                         // return whether this line is empty
bool full() const;                          // return whether this line is full
void push_back(const char&);                // append character to the end of this line
void pop_back();                            // remove the last character in this line

friend std::ostream& operator<<(std::ostream&, const Line&);    // print this line
friend std::istream& operator>>(std::istream&, Line&);          // reads into this line
private:
char* linePtr;          // pointer to the first character in this line
int lineLength;         // length of this line
int lineCapacity;       // storage capacity of the line
};
// definitions of public member functions and utility functions of the Line class.
// definitions of friend overloaded input and output operators

#include "stdafx.h"
#include "Line.h"
#include <cstring>

using namespace std;

// ctor: construct this line from a given C-string
Line::Line(const char* cstring) {
    lineLength = strlen(cstring) + 1;                   
    lineCapacity = lineLength - 1;
    linePtr = new char[lineCapacity + 1] {};                        // create a new character pointer of appropriate size for the line object
    strncpy_s(linePtr, lineLength, cstring, lineLength);                // copy cstring into line with strncpy_s instead of strncpy due to Visual Studio Error with using strncpy
}


// ctor: construct this line from a given character
Line::Line(char ch) : linePtr{ new char[2] { ch, NULL } }, lineLength{ 2 }, lineCapacity{ 1 } {
    /* empty body */
}


// virtual dtor
Line::~Line() {
    delete[] linePtr;           // release line space

    // reset member data
    linePtr = nullptr;          
    lineCapacity = 0;
    lineLength = 1;
}


// copy-ctor
Line::Line(const Line& rhs) : linePtr{ new char[rhs.lineCapacity + 1] {} },
                          lineLength    {rhs.lineLength},
                          lineCapacity{rhs.lineCapacity} {
    strncpy_s(this->linePtr, this->lineLength, rhs.linePtr, rhs.lineLength);            // strncpy_s instead of strncpy due to Visual Studio Error with using strncpy
}


// copy-assignment operator
const Line& Line::operator=(const Line& rhs) {
    if (&rhs != this) {                                                                     // avoid self-assignment

        // if the two sides are of different lengths or capacities;
        // deallocate the lhs line, then allocate new lhs line
        if (this->lineCapacity != rhs.lineCapacity || this->lineLength != rhs.lineLength) {
            delete[] linePtr;                                                               // deallocate lhs line
            this->lineCapacity = rhs.lineCapacity;
            this->lineLength = rhs.lineLength;
            this->linePtr = new char[rhs.lineCapacity + 1] {};
    }

    strncpy_s(this->linePtr, this->lineLength, rhs.linePtr, rhs.lineLength);
}

return *this;
}


// return C-style version of this line
const char* Line::cstr() const {
    return linePtr;
}


// return length of this line
int Line::length() const {
    return lineLength;
}


// return capacity of this line
int Line::capacity() const {
   return lineCapacity;
}


// double capacity of line in case line is full
void Line::resize() {
    if (full()) {
        char* tempPtr{ new char[lineCapacity + 1] {} };                 // data holder to prevent loss of data
         strncpy_s(tempPtr, lineLength, linePtr, lineLength);            // strncpy_s instead of strncpy due to Visual Studio Error with using strncpy
        delete[] linePtr;                                                // deallocate the line;

         // double capacity
        if (lineCapacity == 0) {                                
            lineCapacity = 1;
        }
        else {
             lineCapacity *= 2;                                     
        }
        linePtr = new char[lineCapacity + 1] {};                        // create a new line with double capacity
        strncpy_s(linePtr, lineLength, tempPtr, lineLength);
        delete[] tempPtr;                                               // deallocate the temporary data holder
        tempPtr = nullptr;
    }
}


// return whether this line is empty
bool Line::empty() const {
    return (lineLength == 1 && lineCapacity >= lineLength);         // null terminating character at the beginning of line
}


// return whether this line is full
bool Line::full() const {
    return lineCapacity == (lineLength - 1);                        // only occurs when terminating NULL character at end of line;

}

// append character to the end of this line
// appending a NULL character has no effect
void Line::push_back(const char& ch) {
    if (ch != NULL) {
        resize();
        ++lineLength;
        linePtr[lineLength - 2] = ch;
        linePtr[lineLength - 1] = NULL;
    }
}


// remove the last character in this line
void Line::pop_back() {
    if (!empty()) {
        linePtr[lineLength - 2] = NULL;     
        --lineLength;
    }
    else {
        cout << "Line is empty. Nothing to remove.\n";
    }
} 


// print this line
ostream& operator<<(ostream& output, const Line& line) {
    output << line.cstr() << endl;

    return output;                                          // enables cascading: cout << x << y        
}


// reads into this line
istream& operator>>(istream& input, Line& line) {
    char ch{ NULL };
    cin >> noskipws;                                            // read-in whitespaces 
    while (ch != '\n') {                                
        input >> ch;
        line.push_back(ch);
    }

    return input;                                           // enables cascading: cin >> x >> y 
}

0 个答案:

没有答案