让我通过一个例子来解释我所要求的。想象一下,我有一个汽车课。 现在,这辆车可能还有很多额外功能:
我想用这些选项的任意组合创建类。任何这些选项都需要一些数据成员。想象一下,这个班级现在看起来像这样:
class Car {
public:
bool FourDoors;
bool AutomaticDoorLocking;
bool FourWheelDrive;
Door doors[4]; //4 only needed if FourDoors=true
DoorLockingElectronic doorElectronic; //Only needed if AutomaticDoorLocking=true
TransmissionsShafts[4]; //4 only needed for FourWheelDrive=true
void lockDoors() {
if (AutomaticDoorLocking) {
doorElectronic.lockDoors();
} else {
// Do manual door locking
}
}
};
到目前为止一切都那么好,但现在我想制造很多车,这么多内存变得至关重要。而且我不需要大多数汽车的大部分额外功能。 我可以创建一个基类,并派生启用或禁用这些选项的类。 但是我必须创建2 ^ {#extras}类来创建所有可能的组合,并且有很多双重代码。
所以我想也许可以使用模板? (这是问题)。
我可以想象有一个标志模板,并像这样重写lockDoors:
template<int flags>
void Car<flags>::lockDoors() {
if (flags | AutomicDoorLockingFlag) {
doorElectronic.lockDoors();
} else {
// Do manual door locking
}
}
奇妙!但是Car&lt; 0&gt;类Car仍然需要很多不必要的空间。所以:
我可以根据模板参数以某种方式包含或排除类成员吗?
其他想法也欢迎如何应对这种情况!
答案 0 :(得分:6)
您想要使用策略类:
class FourDoorPolicy { Door m_doors[4]; ... };
class TwoDoorPolicy { Door m_doors[2]; ... };
class AutoDoorLockingPolicy { ... };
class ManualDoorLockingPolicy { void lockDoors(); ... };
class FourWheelDrivePolicy { TransmissionShafts m_shafts[4]; ... };
class TwoWheelDrivePolicy { TransmissionShafts m_shafts[2]; ... };
template <class DoorPolicy = TwoDoorPolicy,
class LockingPolicy = ManualDoorLockingPolicy,
class DrivePolicy = TwoWheelDrivePolicy>
class Car : public DoorPolicy, public LockingPolicy, public DrivePolicy
{
...
};
将所有特定于策略的内容(例如lockDoors()
函数)放在策略类中而不是Car
类中。 Car
类继承了这些,这是一种组合形式(即您将所有功能构建到Car
类中)。
请注意,您应该为所有策略类提供protected
,非virtual
析构函数,以便它们只能作为派生类的一部分进行实例化。
然后以正常的模板方式实例化自定义汽车:
Car<FourDoorPolicy, AutoDoorLockingPolicy, TwoWheelDrivePolicy> myCar;
当然,您可以使用typedef
来帮助解决这个问题(C ++ 0x中的模板别名也会有很大帮助)。
答案 1 :(得分:1)
你可能应该研究Policy-based design。基本上,它包括作为策略类中的外部化行为,并使用适当的策略实例化模板汽车对象。策略类负责封装给定的行为。
从实现的角度来看:Car
成为一个模板,其中每个类型参数对应于给定的策略(例如:DoorLockingPolicy
)。然后,您可以根据您选择的类型“配置”您的汽车模板:ManualDoorLockingPolicy
或AutomaticDoorLockingPolicy
。
template<class DoorLockingPolicy /*, class DoorsPolicy, ... */>
class Car : DoorLockingPolicy
{
public:
void lockDoors()
{
/* ... */
DoorLockingPolicy::lockDoors();
}
};
struct ManualDoorLockingPolicy
{
void lockDoors() { /* ... */ }
};
struct AutomaticDoorLockingPolicy
{
void lockDoors() { /* ... */ }
};
int main()
{
Car<ManualDoorLockingPolicy> car1;
Car<AutomaticDoorLockingPolicy> car2;
}
从性能的角度来看,基于策略的设计是实现“不为不使用的东西付费”的好方法:
Car
模板可以从其策略中私下继承,并从空基优化中受益。现代C ++设计(Andrei Alexandrescu)再一次对这个主题进行了很好的阅读。
答案 2 :(得分:0)
一种可能性是引入要素类。要素类将具有某种唯一标识符(我已经使用int
作为它的地狱,但boost::uuids::uuid
将更为可取。除了定义某种功能外,它什么也没做:
class Feature
{
private:
int m_nUniqueID;
protected:
Feature(int _uniqueID) : m_nUniqueID(_uniqueID) {};
virtual ~Feature(){};
public:
const int& getUniqueID const {return(m_nUniqueID);};
}; // eo class Feature
由此,我们可以得出更具体的特征:
class DoorsFeature : public Feature
{
private:
int m_nDoors;
public:
static const int UniqueId;
DoorsFeature(int numDoors) : Feature(UniqueId), m_nDoors(numDoors){};
virtual ~DoorsFeature(){};
void lockDoors() { /* lock the doors */ };
}; // eo class DoorsFeature
class ABSFeature : public Feature
{
public:
static const int UniqueId;
ABSFeature() : Feature(UniqueId){};
virtual ~ABSFeature(){};
}; // eo class ABSFeature
以及汽车可以拥有的任何功能。注意我不会将 wheel 作为一个特征,因为,尽管数量可能不同,但所有汽车都有轮子。我指的是各种各样的特性,例如电子门,ABS,等等。突然间,你的车成了一个更简单的容器:
class Car
{
private:
int m_nWheels;
std::string m_Colour;
std::vector<Feature> m_Features;
protected:
public:
Car();
~Car();
void addFeature(Feature& _feature) {m_Features.push_back(_feature);};
Feature getFeature(int _featureId) const;
void lockDoors()
{
DoorsFeature& doorsFeature(static_cast<DoorsFeature&>(getFeature(DoorsFeature::UniqueId)));
doorsFeature.lockDoors();
} // eo lockDoors
}; // eo class Car
鉴于此,您还可以更进一步,引入命名功能集(非常类似于您从经销商/制造商处获得的选项包),可以自动应用于汽车或各种品牌,型号和系列
显然,我已经离开了很多。您可能希望将汽车的引用传递给每个功能,或者不这样做。
答案 3 :(得分:0)
我认为问题在于你正在尝试定义一个能够代表所有可能版本的“Car”的单个类,这意味着每个实例都包含能够代表所有可能的汽车的成员数据。这个问题在很久以前就被传统的继承所解决了。
定义基类中所有汽车共有的功能。然后派生添加功能的特定类(以及增加内存占用的成员变量)。只需通过实例化正确的子类即可最小化内存。每个实例仅包含对该特定类型的Car重要的成员。
答案 4 :(得分:-1)
尝试重写代码以使用vector
而不是数组。你可以只使用你需要的空间,而且也更容易。
#include <vector>
#include <memory>
class Car
{
public:
int getDoorCount() { return doors.size(); }
bool isFourWheelDrive() { return transmissionShafts.size() == 4; }
bool areDoorsAutoLocking() { return automaticDoorLocking.get() != NULL; }
void lockDoors() {
if (automaticDoorLocking.get() != NULL) {
automaticDoorLocking->lockDoors();
} else {
// Do manual door locking
}
}
private:
std::vector<Door> doors;
std::vector<TransmissionsShafts> transmissionShafts;
std::auto_ptr<DoorLockingElectronic> automaticDoorLocking;
};
注意Car
现在如何支持掀背车(5门)。