2014-11-26 2 views
0

Я знаю, что этот вопрос уже задан, но ни один из ответов, которые у меня пока не обнаружены, кажется достаточным. Я создаю вектор указателей на базовый класс и добавляю к нему всевозможные производные классы. Теперь базовый класс имеет виртуальную функцию, которая переопределяется во всех производных классах и уникальна для каждого из них. Поэтому, когда я просматриваю вектор и извлекаю эти объекты и вызываю функцию на этом объекте, мне нужно, чтобы он вызывал правильный, но все, что он будет делать, это вызвать версию базового класса. Я даже пытаюсь вернуть отдельные элементы в свой первоначальный класс, когда я извлекаю их из вектора, но они отказываются быть брошенными! напримерКастинг объектов в векторе в C++

vector<base*> myBase; 

DerivedClass *myDerived = static_cast<DerivedClass> myBase[i]; 

Это не работает, несмотря на то, что все, что я читал, предполагает, что он должен. Мой отладчик говорит, что, несмотря на все это, myDerived по-прежнему имеет базу типов и вызывается версия моей виртуальной функции.

Любые идеи?

class BankAccount { 
public: 
BankAccount(string namein, string typein){ 
    name = namein; 
    type = typein; 
    balance = 0; 
} 
virtual string getType(); 
virtual void printTransactions() = 0; 
virtual int withdraw(double amt){ 
    return getBalance() -amt; 
} 
}; 

class SavingsAccount: public BankAccount { 
public: 
SavingsAccount(string namein, string typein); 
void addTransaction(string transType, string name); 
virtual int withdraw(double amt); 
void printTransactions(); 
virtual string getType(); 

private: 

}; 

SavingsAccount::SavingsAccount(string namein, string typein): BankAccount(namein, typein) { 

} 

int SavingsAccount::withdraw(double amt){ 
double aBal = getBalance() - amt; 
if (aBal > 0){ 
setBalance(aBal); 
} 
return getBalance() - amt; 

} 


class CheckingAccount: public SavingsAccount { 
public: 
CheckingAccount(string nameIn, string typein): SavingsAccount(nameIn, typein){ 

} 
virtual int withdraw(double amt); 
void printTransactions(); 
string getType(){ 
    return "Checking"; 
} 

}; 

int CheckingAccount::withdraw(double amtIn){ 
double newBal = getBalance() - amtIn; 
if (newBal < 500.00 && newBal > 2.49) { 
    setBalance(newBal - 2.50); 
} 
return newBal; 

}

int main(int argc, const char * argv[]) 
{ 
vector<BankAccount*> myAccts; 
SavingsAccount *mySav; 
CD *myCD; 
CheckingAccount *myCheck; 

switch (option) { 
     case 1: { 
      string name; 
      string type; 
      cout << "Enter name: "; 
      cin >> name; 
      getline(cin, dump); 
      cout << "Enter account type: "; 
      cin >> type; 
      getline(cin, dump); 
      if (type.compare("Checking") == 0) { 
       CheckingAccount myCheck1 = CheckingAccount(name, type); 
       myAccts.push_back(&myCheck1); 

      } 
     case 3:{ 
     for (int x = 0; x < myAccts.size(); x++) { 
       if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) { 
        if (type == "Savings") { 
         mySav = static_cast<SavingsAccount*>(myAccts[x]); 
         double y = mySav->withdraw(amt); 
         if (y < 0){ 
          cout << "Insufficient funds!"; 
          } 
        } 
        if (type == "Checking") { 
         myCheck = myAccts[x]->GetDerived(); 
         double y = myCheck->withdraw(amt); 
         if (y < 0){ 
          cout << "Insufficient funds!"; 
          } 
         if (y < 497.5) { 
          cout << "Withdrawal fee: $ 2.50" << endl; 
         } 


        } 

} 

Проверка счета является дочерним сберегательный счет. Сожалею.

+1

DerivedClass * myDerived = static_cast myBase [i]; – radar

+1

Использовать 'dynamic_cast' - лучше, чем' static_cast' –

+0

динамический сброс возвращает Null – user3712524

ответ

4

Ваша концепция правильная и не требует никакого литья. Весь смысл виртуальных функций заключается в том, что если вы держите указатель базового класса или ссылку и вызываете виртуальную функцию, то самая производная версия этой функции будет вызываться во время выполнения.

Ошибка Я вижу это:

if (type.compare("Checking") == 0) { 
     CheckingAccount myCheck1 = CheckingAccount(name, type); 
     myAccts.push_back(&myCheck1); 

Вы создаете чековый счет в стеке, а затем взяв его адрес и нажав этот адрес в вектор. В конце if блок myCheck1 выйдет за пределы области действия и будет уничтожен. У вашего вектора будет адрес в папку в стеке, и у вас будет неопределенное поведение.

Вместо делать:

if (type.compare("Checking") == 0) { 
     myAccts.push_back(new CheckingAccount(name, type)); 

И аналогично для других типов. Избавьтесь от всех этих бросков. В этой версии вам нужно будет удалить все элементы в векторе в конце. Если вы используете std::vector<std::unique_ptr<BankAccount>>, тогда unique_ptr позаботится о очистке выделенных объектов.

0

Вы пробовали что-то вроде этого?

class base 
{ 
public: 

inline DerivedClass *GetDerived() {return (DerivedClass*)this;} 

... 
}; 

DerivedClass *myDerived = myBase[i]->GetDerived(); 
+1

Вы должны использовать 'dynamic_cast' при нажатии вниз, так как это позволяет вам проверить, что объект, который вы являетесь оболочкой, действительно является производным типом. В противном случае результат приведения не имеет особого смысла, и это может создать много головных болей. – vsoftco

3

Вы должны использовать new создавать свои счета ... у вас есть:

if (...) 
{ 
    CheckingAccount myCheck1 = CheckingAccount(name, type); 
    myAccts.push_back(&myCheck1); 
} 

... myCheck1 разрушается при выходе, что if рамки, оставляя myAccts с указателем на эффективное случайное место на стек, который имеет неопределенное поведение при доступе. Изменить на:

if (type == "Checking") 
    myAccts.push_back(new CheckingAccount(name, type)); 

Затем вам нужно будет иметь соответствующий delete сек для vector элементов. Googling «C++ new delete tutorial» будет хорошей идеей.Следующий этап - узнать, как использовать интеллектуальные указатели, например - std::shared_pointer - которые снимают бремя запоминания с delete.

«Случай 3» может быть исправлен/упрощен до:

  for (int x = 0; x < myAccts.size(); x++) 
      if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) { 
       double y = myAccts[x]->withdraw(amt); 
       if (y < 0) 
        cout << "Insufficient funds!"; 
       if (type == "Checking" && y < 497.5) 
         cout << "Withdrawal fee: $ 2.50" << endl; 
      } 

Обратите внимание, в частности, double y = myAccts[x]->withdraw(amt); - виртуальная функция гарантирует, что правильная версия называется без вас сделать что-нибудь типа специфичное в призвании код.

Смежные вопросы