Полиморфизм переменных-членов - PullRequest
0 голосов
/ 19 января 2019

Я начинаю с C ++, и у меня возникают проблемы с использованием полиморфизма, особенно когда я хочу использовать его в конструкторах нового класса.Я знаю, что вопрос был обработан здесь , но я не понял, и мой случай немного отличается.

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

#include <iostream>
#include <string>
#include <headers.h>
using namespace std;

void Display(Car &c)
{
    c.Show();
}

int main()
{
    Car Clio(50);
    SportCar Ferrari(200,200);
    Clio.Show();
    Ferrari.Show();

    Display(Ferrari);

    Race(Ferrari, Track());

    return 0;
}

Файл headers.h:

#ifndef CAR_H
#define CAR_H

class Car
{
    public:
        Car(double s);
        Car();
        virtual void Show() const;

    protected:
        double m_Speed;

    private:
};

#endif // CAR_H


#ifndef SPORTCAR_H
#define SPORTCAR_H

class SportCar : public Car
{
    public:
        SportCar(double s, double p);
        SportCar();
        virtual void Show() const;

    protected:

    private:
        double m_Price;
};

#endif // SPORTCAR_H


#ifndef TRACK_H
#define SPORTCAR_H

class Track
{
    public:
        Track(double l);
        Track();

    protected:

    private:
        double m_Length;
};

#endif // SPORTCAR_H

#ifndef RACE_H
#define RACE_H


class Race
{
    public:
        Race(const Car& , Track t);

    protected:
        Car &m_Car;
        Track m_Track;

    private:
};

#endif // RACE_H

И, наконец, файл src.cpp:

#include <string>
#include <iostream>
#include <headers.h>
using namespace std;

Car::Car(double s)
{
     m_Speed = s;
}

Car::Car()
{
    m_Speed = 50;
}

void Car::Show() const
{
    cout << "I'm a car" << endl;
}

SportCar::SportCar(double s, double p) : Car(s)
{
    m_Price = p;
}

SportCar::SportCar() : Car()
{
    m_Price = 200;
}

void SportCar::Show() const
{
    cout << "I'm a sportcar" << endl;
}

Track::Track(double l)
{
    m_Length = l;
}

Track::Track()
{
    m_Length = 10;
}

Race::Race(const Car& c, Track t)
{
    m_Car = c;
    m_Track = t;
    m_Car.Show();
}

InРезюме У меня есть два разных класса автомобилей, один из которых (SportCart) наследуется от другого (Car) с двумя разными Show() методами.И у меня есть класс Race, члены которого являются своего рода машиной, а Track.Когда я использую конструктор Race, я не могу передать в аргументе машину как SportCar.

В результате я получаю:

I'm a car
I'm a sportcar
I'm a sportcar
I'm a car

И я хочу:

I'm a car
I'm a sportcar
I'm a sportcar
I'm a sportcar

Я пытаюсь использовать такие ссылки:

protected:
    Car &m_Car;
    Track m_Track;

Но это тоже не работает, у меня есть эта ошибка, которую я не могу исправить:

||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
E:\documents\c++\test\src\src.cpp||In constructor 'Race::Race(const Car&, Track)':|
E:\documents\c++\test\src\src.cpp|46|error: uninitialized reference member in 'class Car&' [-fpermissive]|
include\headers.h|66|note: 'Car& Race::m_Car' should be initialized|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Обратите внимание, что в C ++ «инициализация» (создание объекта определенным образом, например, std::string str = "hi";) и «присваивание» (изменение значения существующего объекта, например, str = "hi";) - это две разные вещи.

Когда вы пишете конструктор, как

Car::Car(double s)
{
     m_Speed = s;
}

C ++ нуждается в объекте, и все его члены существуют, и поэтому уже инициализированы к тому времени, как вы достигнете первого {. Оператор m_Speed = s; является присваиванием, а не инициализацией. Так как вы не указали, как m_Speed должен быть инициализирован, C ++ вставляет логику для «инициализации по умолчанию» перед началом конструктора (хотя для базового типа, такого как double, это просто означает, что оно имеет неопределенное значение до назначения ).

Обычно это не имеет значения для члена типа double. Но это может быть для члена типа класса, и это определенно подходит для члена ссылочного типа: ссылка ДОЛЖНА быть инициализирована, потому что ссылка всегда должна ссылаться на некоторый объект, а присвоение, левая часть которого всегда является ссылочной переменной, всегда назначает этому указанному объекту; нет способа изменить объект, на который ссылается ссылка.

Способ указать, как конструктор инициализирует элементы, использует список инициализаторов элементов:

Car::Car(double s)
    : m_Speed(s)
{}

Race::Race(const Car& c, Track t)
    : m_Car(c), m_Track(t)
{
    m_Car.Show();
}

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

[Примечание 1: показанный выше конструктор Race все равно не будет работать из-за другой проблемы: вы не можете инициализировать ссылку Car& из const Car&. Вам нужно будет либо изменить конструктор, чтобы он принимал не const параметр, либо изменить член на тип const Car&. Не const параметр также позволит избежать потенциальных проблем с привязкой к временному.]

[Примечание 2: Другой способ указать инициализатор для членов класса - поставить = something; после объявления члена в классе. Этот инициализатор по умолчанию будет использоваться, когда конструктор не указывает инициализатор для этого члена и в неявно определенном конструкторе по умолчанию, если таковой имеется. Это может быть удобно, если вы хотите, чтобы несколько конструкторов использовали один и тот же инициализатор.]

0 голосов
/ 19 января 2019

Проблема в том, что ссылка должна быть инициализирована, как указано в сообщении об ошибке.Чтобы сделать это в конструкторе, мы используем список инициализаторов .

Race::Race(Car& c, Track t) : m_Car(c), m_Track(t)
{
    m_Car.Show();
}

Редактировать: m_Track здесь не нужно инициализировать, но рекомендуется всегда использоватьсписок инициализатора, если это возможно, и он также более эффективен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...