我从C ++开始,我很难使用多态性,尤其是当我想在新类的构造函数中使用它时。我知道该问题已得到here的处理,但我不明白,我的情况也有所不同。
要了解如何使用它,我构建了这个小程序。这是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();
}
总而言之,我有两种不同的汽车类别,其中一种(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)) ===|
谢谢您的帮助。
答案 0 :(得分:2)
请注意,在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;
放在类内的成员声明之后。当构造函数未为该成员指定初始化程序时,将在隐式定义的默认构造函数(如果有)中使用此默认初始化程序。当您希望多个构造函数使用相同的初始化程序时,这会很方便。]
答案 1 :(得分:1)
问题在于,必须在错误消息指出时初始化引用。为此,我们使用initializer list。
Race::Race(Car& c, Track t) : m_Car(c), m_Track(t)
{
m_Car.Show();
}
编辑:m_Track不需要在这里初始化,但是,如果可能的话,始终使用初始化器列表是一种很好的做法,而且效率更高。