如何解决将属性传递给基类的机制
将属性从派生类传递到基类的机制是什么?
- 基本ctor可以访问它们。
- 它们可以轻松地存储在STL容器中。
- 外面的任何人都可以访问它们,只能在派生类上“看到”。
- 有效性并不是很有价值。
属性是一个与派生类的每个对象相关的常数。
解决方法
如果您的问题是“将属性从派生类传递到基类的机制是什么?”有两种方法可以做到这一点。
- 最常见的方法是通过成员初始值设定项列表 初始化父类
#include <iostream>
class Base
{
public:
Base(const char *a)
{
std::cout << a << std::endl;
}
};
class Derived : public Base
{
public:
Derived(const char *a)
: Base{a} { }
};
int main()
{
Derived d{"Parent initialization through member initializer list"};
// console output: Parent initialization through member initializer list
}
- 使用键通过获取构造函数继承
#include <iostream>
class Base
{
public:
Base(const char *a)
{
std::cout << a << std::endl;
}
};
class Derived : public Base
{
public:
using Base::Base;
};
int main()
{
Derived d{"Parent class initialization through constructor inheritance"};
// console output: Parent class initialization through constructor inheritance
}
看看带有模板类的有用示例
#include <iostream>
#include <vector>
template<class T>
class custom_vector : public std::vector<T>
{
public:
// I will inherit all std::vector constructors
using std::vector<T>::vector;
// ...
};
int main()
{
// Inizializer list constructor
custom_vector<int> v{1,2,3,4,5};
for (auto x : v) std::cout << x << std::endl;
// 1 2 3 4 5
// Fixed-allocation with default value constructor
custom_vector<char> v2(10,'A');
for (auto x : v2) std::cout << x << std::endl;
// A A A A A A A A A A
}
不用使用std :: vector
在您的示例中,我注意到一些设计缺陷
- 虚拟函数不用于将属性传递给基类
- 我不明白你为什么提到模板
- 您不应重复使用virtual关键字,因为它在派生类中已经是虚拟的,可以使用override关键字。
- 通常不建议使用部分实现的抽象类,您应该考虑从BaseVehicle中删除m_image和m_speed。在某些情况下,在抽象类中进行一些实现实际上是有用的,但只有在您有充分理由的情况下才这样做。
- 在抽象类的构造函数中具有类似* table.registerVehicle( this,number)的语句是一种不良的设计症状。
您可以虚拟或非虚拟方式进行操作。但是,要回答其中哪一个最好,让我们检查一下您的示例:
class Bicycle: public BaseVehicle
{
public:
Bicycle(VehicleTable& table,Number number): BaseVehicle(table,number) {}
virtual float getMaxSpeed() const { return 40.0f; } // constant
virtual float getWeight() const { return 10.0f; } // constant
virtual float getLength() const { return 2.3f; } // constant
virtual int getWheels() const { return 2; } // constant
};
这些函数中的每个函数都返回一个常量,但仍需要进行虚拟调用才能获取该常量。这是不理想的做法,因为您需要执行(昂贵的)虚拟调用才能获取每个值。
更好的方法:使用struct
相反,最好将这些常量传递给父级的构造函数,并将这些常量存储在基类中。这样,您根本不需要访问vtable
中的BaseVehicle
,只需直接在基类内部访问它们即可。像这样:
struct VehicleStats {
float maxSpeed;
float weight;
float length;
int wheels;
};
// BaseVehicle's constructor now becomes this:
BaseVehicle(VehicleTable& table,Number number,VehicleStats stats)
或者,您只能在virtual
中创建一个BaseVehicle
函数:
virtual VehicleStats getStats() const = 0;
这肯定比创建四个单独的函数更好。
替代方法:使用enum
您还可以将代表车辆类型的enum
传递给父级。例如:
enum class VehicleType {
BICYCLE,CAR
};
// BaseVehicle's constructor now becomes this:
BaseVehicle(VehicleTable& table,VehicleType stats)
然后您将统计信息全局存储:
static const std::map<VehicleType,VehicleStats> globalStatsMap;
如果您有大量的统计信息并且不想增加基类的内存大小,那么这是一种非常好的方法。现在,您也完全不需要BaseVehicle
的实例,并且仍然可以根据类型查找属性。
根据显示的内容,您根本不需要继承:
struct VehicleAttributes
{
float maxSpeed;
float weight;
float length;
int wheelsCount;
};
class Vehicle
{
private:
Vehicle(VehicleTable& table,const VehicleAttributes& attributes): m_image(attributes.length,attributes.wheelsCount),m_attributes(&attributes)
{
table.registerVehicle(*this,number);
}
public:
static Vehicle BiCycle(VehicleTable& table,Number number)
{
static const VehicleAttributes bicycleAttributes{40,10,2.3,2};
return Vehicle(table,number,bicycleAttributes);
}
static Vehicle Car(VehicleTable& table,Number number)
{
static const VehicleAttributes carAttributes{88,42,2.5,4};
return Vehicle(table,carAttributes);
}
const VehicleAttributes& getAttributes() const { return *m_attributes; }
private:
Image m_image;
const VehicleAttributes* m_attributes = nullptr;
float m_speed = 0; // the current speed
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。