2014-09-09 2 views
0

Я практикуюсь с классами и векторами и сохраняю объекты в векторах. После хранения объекта базового класса и объекта класса, который наследуется от него, мой компилятор возвращает ошибку, которая не существует унаследованного объекта класса. Вот что я предполагаю, являются важными биты:Хранение объектов в векторе, компилятор говорит, что элемент не существует

Класс автомобиля и класс Спорткар, который наследует от автомобиля

class Car 
{ 
    public: 
     Car(); 
     void stop(); 
     int get_speed() const; 
     void new_speed(int fspeed); 

    protected: 
     int speed; 
}; 

class Sportscar : public Car 
{ 
    public: 
     Sportscar(); 
     void turbo(); 

    private: 
     bool hasTurbo; 
}; 

Сохранение объектов в векторных автомобилей:

vector<Car*> cars(2); 

    cars[0] = new Car(); 
    cars[1] = new Sportscar(); 

Доступ к cars[0] и cars[1], где cars[0] имеет доступ к штрафу, но cars[1] нет:

cars[1]->turbo(); 
cars[0]->new_speed(cars[0]->get_speed()); 

Вот полный код, который немного повсюду, так как я не был уверен, что изначально, когда я собирался с этой маленькой игре автомобиля:

#include <iostream> 
#include <cstdlib> 
#include <vector> 
using namespace std; 

class Car 
{ 
    public: 
     Car(); 
     void stop(); 
     int get_speed() const; 
     void new_speed(int fspeed); 

    protected: 
     int speed; 
}; 

class Sportscar : public Car 
{ 
    public: 
     Sportscar(); 
     void turbo(); 

    private: 
     bool hasTurbo; 
}; 

// Constructor for class Car 
Car::Car() 
{ 
    speed = 1; 
} 

// Function to stop the car 
void Car::stop() 
{ 
    speed = 0; 

    cout << "You stop the car.\n" << endl; 
} 

// Function to get current speed of the car 
int Car::get_speed() const 
{ 
    return speed; 
} 

// Function to "accelerate" the car 
void Car::new_speed(int fspeed) 
{ 
    int newspeed; 

    cout << "Speed up by how many mp/h? "; 
    cin >> newspeed; 

    speed = (fspeed + newspeed); 

    cout << "You speed up.\n" << endl; 
} 

// Sportscar constructor to set hasTurbo to 0 (no) 
Sportscar::Sportscar() 
    // Not sure if this is necessary 
    : Car() 
{ 
    hasTurbo = 0; 
} 

// Function to designate if the car has turbo 
void Sportscar::turbo() 
{ 
    hasTurbo = 1; 

    cout << "You have activated turbo and have greater acceleration.\n" << endl; 
} 

int main(void) 
{ 
    vector<Car*> cars(2); 

    cars[0] = new Car(); 
    cars[1] = new Sportscar(); 

    //Car drive; 
    //Sportscar drivefast; 
    char ans; 
    char sport; 

    // Asks user for input A, B, C, or Q until user chooses Q to quit 
    while(1) 
    { 
     cout << "Enter 'A' for current speed, 'B' to speed up, or 'C' to stop. 'Q' to quit." << endl; 
     cin >> ans; 

     // If users chooses A, calls get_speed() function and outputs current speed 
     if (ans == 'A') 
     { 
      cout << "Your current speed is " << cars[0]->get_speed() << " mp/h.\n" << endl; 
     } 

     // If user chooses B, calls new_speed() function to increase speed according to 
     // user's specifications 
     else if (ans == 'B') 
     { 
      // Asks user if they have turbo Y/N 
      cout << "Do you want to use turbo? Y/N: "; 
      cin >> sport; 

      // If user does have turbo, hasTurbo is set to 1 (yes) and function 
      // new_speed() is called 
      if (sport == 'Y') 
      { 
       cars[1]->turbo(); 
       cars[0]->new_speed(cars[0]->get_speed()); 
      } 

      // If user does not have turbo, hasTurbo stays at 0 (no) and function 
      // new_speed() is called 
      else if (sport == 'N') 
      { 
       cars[0]->new_speed(cars[0]->get_speed()); 
      } 

      // If user answers other can Y or N, tells user input is incorrect 
      else 
      { 
       cout << "Incorrect input.\n" << endl; 
      } 
     } 

     // If user chooses C, calls stop() function and reduces car's speed to 0 
     else if (ans == 'C') 
     { 
      cars[0]->stop(); 
     } 

     // If user chooses Q, program ends 
     else if (ans == 'Q') 
     { 
      exit(0); 
     } 

     // If user chooses other than A, B, C, or Q, tells user input is incorrect 
     else 
     { 
      cout << "Incorrect input.\n" << endl; 
     } 
    } 
} 

Наконец, вот моя ошибка компилятора:

enter image description here

Я хотел бы отметить, что если я удалить строку с доступом к cars[1], программа компилируется и работает отлично.

ответ

2

Ваш вектор объявлен как вектор Car*. Объект типа Car не имеет функции-члена turbo. Вам нужно привести указатель к Sportscar* типа:

static_cast<Sportscar*>(cars[1])->turbo(); 
+1

Примечание. Это вызывает неопределенное поведение, если 'cars [1]' на самом деле не был «спортом». Также это вызовет UB 'delete cars [1]', не повторяя static_cast. Превращение 'Car' polymorphic, вероятно, является лучшей причиной. –

0

cars является vector<Car*> и Car действительно не имеет функции в turbo() члена.

C++ использует статический поиск имени. Это не будет выглядеть на Car*, см., Что во время выполнения он указывает на Sportscar, а затем ищет turbo в Sportscar.

Если вы хотите, что динамическое поведение, то вы должны написать его самостоятельно (после фиксации базового класса на самом деле поддержки полиморфизма):

if (auto sc = dynamic_cast<Sportscar*>(cars[1])) { 
    sc->turbo(); 
} else { 
    std::cout << "cars[1] is not a Sportscar\n"; 
} 

(конечно, так как вы знаете, что это спорткар вы могли бы безоговорочно static_cast это, а)


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

struct Base { 
    virtual void foo() { std::cout << "Base\n"; } 
    virtual ~Base() {} 
}; 

struct Derived : Base { 
    virtual void foo() override { std::cout << "Derived\n"; } 
}; 

int main() { 
    Base *b = new Derived; 
    b->foo(); // prints "Derived" 
} 

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

+1

'dynamic_cast' работает только на полиморфных классах; «Автомобиль» должен иметь виртуальную функцию (желательно деструктор) для того, чтобы ее выполняли. –

+0

@MattMcNabb Да, это правда. Я не заметил, что это еще не было. – bames53

0

Когда ваш класс SportsCar наследуется от автомобиля, вы можете добавлять методы просто отлично. Когда вы храните SportsCar в векторе, он по-прежнему сохраняет все данные SportsCar, но вы не можете получить к нему доступ, потому что он рассматривается как автомобиль ТОЛЬКО. если вы хотите получить доступ к методу «turbo()», вам необходимо передать объект «cars [1]» в SportsCar.

SportsCar mySportsCar = (SportsCar)cars[1]; 
//Now you can call .turbo() on mySportsCar 

//You could also do it in one line, like so : 
((SportsCar)cars[1]).turbo(); 

Одна вещь, которую вы должны иметь в виду, никогда не приемлю в вашем векторе является SportsCar, и для этого вы должны проверить тип перед заливкой их, или вы получите исключение брошено. Существует несколько способов сделать это, вот один из них:

if(SportsCar *mySportsCar = dynamic_cast<SportsCar*>(&cars[0])) 
{ 
    //Your car was successfully casted, you can use it here 
} 
else 
{ 
    //Your car is not a SportsCar 
} 
+0

downvoted для использования C-style casts; будет обновляться, если вы переписываете использование C++-трансляций. (На самом деле есть некоторые угловые случаи, когда в C++ требуются стили C-стиля, но это не один из них). Кроме того, 'dynamic_cast' работает только в том случае, если база имеет виртуальную функцию. –

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