2011-12-06 106 views
2

我想創建一個Person對象的向量。不過,我真的想要存儲從Person基類派生的Adult,Professor和Student對象。在詢問this question之後,我瞭解到我的問題出現在Object Splicing中,並且它將派生類保存爲Person類,因爲這是該vector的內容。我試圖修改代碼來糾正這種情況,但是我仍然遇到了一些錯誤,需要一些額外的幫助。謝謝!防止對象切片 - C++

這裏是我的main.cpp代碼:

#include "Person.h" 
#include "Professor.h" 
#include "Student.h" 
#include "Adult.h" 
#include <vector> 
#include <string> 
#include <iostream> 
using namespace std; 

template<typename T> void addPerson(vector<Person *> &personVector) { 
    cout << "DEBUG" << endl; 
    personVector.push_back(new T()); 
} 

void addFriend(vector<Person *> &personVector) { 
    bool loop = true; 
    while (loop) { 
     cout << "\nWhich Person would you like to create? " << endl; 
     cout << " 1. Professor" << endl; 
     cout << " 2. Student" << endl; 
     cout << " 3. Adult" << endl; 
     int caseVar; 
     cin >> caseVar; 
     switch (caseVar) { 
     case 1: 
      addPerson<Professor>(personVector); 
      // old incorrect line: addPerson<Professor *>(personVector); 
      loop = false; 
      break; 
     case 2: 
      addPerson<Student>(personVector); 
      // old incorrect line: addPerson<Student *>(personVector); 
      loop = false; 
      break; 
     case 3: 
      addPerson<Adult>(personVector); 
      // old incorrect line: addPerson<Adult *>(personVector); 
      loop = false; 
      break; 
     default: cout << "Unknown Entry Please Try Again." << endl; 
     } 
    } 
} 

void displayFriends(vector<Person *> &personVector) { 
    if (personVector.size() > 1) { 
     for (unsigned i = 0; personVector.size() > i; i++) 
      cout << i+1 << ". " << personVector[i]->getName() << endl; 
      cout << "DEBUG" << endl; 
    } 
} 

void viewFriend(vector<Person *> &personVector) { 
    if (personVector.size() > 1) { 
     displayFriends(personVector); 
     cout << "Which # friend would you like to view? "; 
     int num; 
     cin >> num; 
     personVector[num-1]->coutPerson(); 
    } else if (personVector.size() == 1) { 
     personVector[0]->coutPerson(); 
    } else { 
     cout << "No friends to View." << endl; 
    } 
} 


void deleteElementFromArray(int element, vector<Person *> &personVector) { 
    vector<Person *> newPersonVector; 
    for (unsigned i = 0; personVector.size() > i; i++) 
     if (i != element - 1) 
      newPersonVector.push_back(personVector[i]); 
    personVector = newPersonVector; 
} 

void removeFriend(vector<Person *> &personVector) { 
    if (personVector.size() > 1) { 
     displayFriends(personVector); 
     cout << "Which # friend would you like to remove? "; 
     unsigned num; 
     cin >> num; 
     if (num <= personVector.size()) 
      deleteElementFromArray(num, personVector); 
     else 
      cout << "Invalid Selection" << endl; 
    } else if (personVector.size() == 1) { 
     cout << "Removed one and only friend" << endl; 
    } else { 
     cout << "No friends to Remove." << endl; 
    } 
} 


int main() { 
    vector<Person *> personVector; 
    // Run Main Menu 
    cout << "Friends with Stuff" << endl; 
    cout << "Adding 5 friends to the list" << endl; 
    personVector.push_back(new Person("James")); 
    personVector.push_back(new Person("Martin")); 
    personVector.push_back(new Person("Sammi")); 
    personVector.push_back(new Person("Donny")); 
    personVector.push_back(new Person("Ronald")); 
    bool loop = true; 
    while (loop) { 
     cout << "\nWhat would you like to do? " << endl; 
     cout << " 1. Add New Friend" << endl; 
     cout << " 2. View Friend" << endl; 
     cout << " 3. Remove Friend" << endl; 
     cout << " 4. Clear Friends" << endl; 
     cout << " 5. Get Object" << endl; 
     cout << " 6. Exit" << endl; 
     int caseVar; 
     cin >> caseVar; 
     switch (caseVar) { 
     case 1: 
      addFriend(personVector); 
      break; 
     case 2: 
      viewFriend(personVector); 
      break; 
     case 3: 
      removeFriend(personVector); 
      break; 
     case 4: 
      personVector.clear(); 
      break; 
     case 5: 

      break; 
     case 6: 
      loop = false; 
      break; 
     default: cout << "Unknown Entry Please Try Again." << endl; 
     } 
    } 
} 

我收到以下錯誤

InitializeBuildStatus: 
1> Touching "Debug\FPVisualStudio.unsuccessfulbuild". 
1>ClCompile: 
1> main.cpp 
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Professor **' to 'Person *&&' 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1>   Reason: cannot convert from 'Professor **' to 'Person *' 
1>   Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 
1>   \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(26) : see reference to function template instantiation 'void addPerson<Professor*>(std::vector<_Ty>)' being compiled 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Student **' to 'Person *&&' 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1>   Reason: cannot convert from 'Student **' to 'Person *' 
1>   Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 
1>   \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(30) : see reference to function template instantiation 'void addPerson<Student*>(std::vector<_Ty>)' being compiled 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1>\\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(12): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'Adult **' to 'Person *&&' 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1>   Reason: cannot convert from 'Adult **' to 'Person *' 
1>   Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 
1>   \\cs1\cs_students\mlindahl15\cs172\final project\fpvisualstudio\main.cpp(34) : see reference to function template instantiation 'void addPerson<Adult*>(std::vector<_Ty>)' being compiled 
1>   with 
1>   [ 
1>    _Ty=Person * 
1>   ] 
1> 
1>Build FAILED. 
1> 
1>Time Elapsed 00:00:02.90 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

我相信,它告訴我,我有我的代碼太多的指針。但我不明白爲什麼會這樣。我有指針的唯一地方是說矢量包含我需要在每種情況下重複。這些指針是需要的,所以我沒有對象切片。

Person.h

#ifndef PERSON_H 
#define PERSON_H 
#include <string> 
#include "Date.h" 
#include "PhoneNumber.h" 
using namespace std; 

class Person 
{ 
protected: 
    string name; 
    Date birthday; 
    PhoneNumber phoneNumber; 
    string city, state; 
public: 
    // Constructors 
    Person(); 
    Person(string name) { 
     this->name = name; 
     birthday = Date(); 
     phoneNumber = PhoneNumber("0000000000"); 
     city = "Unknown"; 
     state = "Unknown"; 
    } 
    // Getter and Setter Methods 
    string getName(); 
    void setName(string); 
    Date getBirthday(); 
    // Methods 
    void coutPerson(); 
}; 
#endif 

Person.cpp

#include "Person.h" 
#include "PhoneNumber.h" 
#include "Date.h" 
#include <string> 
#include <iostream> 
using namespace std; 

// Constructors 
Person::Person() { 
    cin.ignore(); 
    cout << "Name? "; 
    getline(cin, name); 
    cout << "Birthday: " << endl; 
    birthday.askUserForDate(); 
    phoneNumber.create(); 
    cout << "City? "; 
    getline(cin, city); 
    cout << "State? "; 
    getline(cin, state); 
} 

// Getter and Setter Methods 
string Person::getName() { 
    return name; 
} 

void Person::setName(string name) { 
    this->name = name; 
} 

void Person::coutPerson() { 
    cout << name << endl; 
    birthday.coutDate(); 
    phoneNumber.coutPhoneNumber(); 
    cout << city << ", " << state << endl; 
} 

// Methods 

Student.h

#ifndef STUDENT_H 
#define STUDENT_H 
#include "Person.h" 
using namespace std; 

class Student : public Person 
{ 
private: 
    string dorm; 
    int dormRoom; 
public: 
    // Constructors 
    Student(); 
    Student(Student &); 
    // Getter and Setter Methods 

    // Methods 
    void coutPerson(); 
}; 
#endif 

Student.cpp

#include "Student.h" 
#include "Person.h" 
#include <string> 
#include <iostream> 
using namespace std; 

// Constructors 
Student::Student() { 
    cin.ignore(); 
    cout << "Dorm? "; 
    getline(cin, dorm); 
    cout << "Dorm Room #? "; 
    cin >> dormRoom; 
} 

// TODO Copy Constructors 
// TODO Deconstructors 
// Overload < > == 

Student::Student(Student &student) { 
    Person::Person(student); 
    dorm = student.dorm; 
    dormRoom = student.dormRoom; 
} 

void Student::coutPerson() { 
    cout << "DEBUG: Student::coutPerson()" << endl; 
    Person::coutPerson(); 
    cout << "Dorm Room: " << this->dorm << " " << this->dormRoom << endl; 
} 

// Methods 
+0

它不告訴你,你有太多的三分球。它告訴你,你在混合不兼容的指針,在這種情況下是'T *'和'T **'。 – moshbear

+0

你試圖實現什麼?你的addPerson將一個向量作爲參數,你想創建一個向量向量? –

回答

2

您的模板參數是指針,但不應該在您的方法中使用,例如template<typename T> void addPerson(...)您使用new創建了一個新實例T,因此您創建了一個指向某人的新指針(即new Person*(),這將導致Person***)。

因此,只是把它這樣的:addPerson<Professor>(personVector);這將轉化成new T()new Professor()從而產生一個Professor*結果。

另一件事:

void deleteElementFromArray(int element, vector<Person *> personVector) { 
    vector<Person *> newPersonVector; 
    for (unsigned i = 0; personVector.size() > i; i++) 
    if (i != element - 1) 
     newPersonVector.push_back(personVector[i]); 
    personVector = newPersonVector; 
} 

首先,你要移除element - 1所以要知道,你不能傳遞0(即element是這裏的一開始的索引)。

其次,您將newPersonVector分配給參數personVector。但是,由於您正在通過值傳遞向量(它被複制),因此該更改在該函數之外將不可見。

您有幾種解決方案,以這樣的:

  1. personVector刪除的項目而不是複製那些不應該被刪除。使用類似personVector.erase(personVector.begin() + element)的東西(請注意,這裏的語法可能不完全正確,但你應該得到它)。
  2. 傳遞指向矢量的指針:void deleteElementFromArray(int element, vector<Person *>* personVector)
  3. 返回新的矢量並替換舊的矢量。這個電話因此變成personVector = removeFriend(personVector);

我個人更喜歡選項1,因爲它重用了矢量,從而減少了複製操作。

+0

+1我完全錯過了刪除部分。 – jv42

+0

@ jv42感謝您的幫助,但我仍然遇到這個問題。我正在創建一個學生(它只問我學生的信息)。但是,當我然後要求它顯示學生信息時,它運行Person :: coutPerson方法而不是運行Student :: coutPerson方法。我添加了我的兩個類.h和.cpp文件,以查看是否存在問題。非常感謝! – michaellindahl

+1

@michaellindahl如果你想覆蓋你需要聲明他們'虛擬'的方法,例如'virtual void coutPerson();'。 – Thomas

2

您需要刪除模板參數中的*

例如:

addPerson<Professor *>(personVector); 

被替換:

addPerson<Professor>(personVector); 

目前,你讓創建Professor **


更新:在你的main(),你應該創建你所使用的,現在 沒有意義,即「採取這種類型的ADRESS」 正在使用new Person("Name")的人,但是一個非常糟糕的想法(將堆棧中創建的對象的地址)。

例如:

personVector.push_back(&Person("James")); 

替換方式:

personVector.push_back(new Person("James")); 

UPDATE2:請注意,你是負責釋放你分配這樣在某些時候的記憶。

+1

實際得到一個人實例的地址應該在_this特定的情況下工作。 'Person'實例將在堆棧上創建,因爲它在'main'範圍內,所以這些實例應該存在於程序的整個生命週期中。然而,這是一種危險的風格,因爲如果在另一種方法中發生這種情況,當該方法的範圍被留下時,實例將被銷燬。因此,在這裏創建使用'new'的人將是更好的方法(+1)。請記住,他負責在從矢量中刪除實例時手動銷燬這些實例。 – Thomas

+0

@托馬斯感謝精度,我已經解決了我的答案。 – jv42

+0

-1:取得堆棧上的一個對象的地址不僅是有效的,它是好的做法(只要你知道容器將在對象之前被銷燬(這是因爲在這裏創建的順序)。另一方面,創建動態對象**絕對是不好的**在這裏實踐,因爲您尚未指定這些對象的所有權(這意味着如果您要使用指針,則push_back()方法需要獲得所有權(例如,ptr_vector 或vector )。 –

1

代碼

addPerson<Professor *>(personVector); 

嘗試修改爲:

addPerson<Professor>(personVector);