假设我在C++中有以下类,我想检查它们的继承:
Vehicle
Motorcar
是一个Vehicle
Aircraft
是Vehicle
Biplane
是Aircraft
是Vehicle
Helicopter
是Aircraft
是一个Vehicle
.
我想写一个方法getClassLineage()
来执行以下操作:
Biplane b;
cout << b.getClassLineage() << endl; // prints "Vehicle--Aircraft--Biplane"
Helicopter h;
cout << h.getClassLineage() << endl; // prints "Vehicle--Aircraft--Helicopter"
Motorcar m;
cout << m.getClassLineage() << endl; // prints "Vehicle--Motorcar"
Run Code Online (Sandbox Code Playgroud)
似乎应该有一种简单的递归方式,通过在超类中编写一次,而不必在每个派生类中复制基本相同的方法.
假设我们愿意申报(伪)Helicopter.className = "Helicopter"
,并
typedef Aircraft baseclass
在每一个派生类的,但尽量避免复制和粘贴getClassLineage()
.
有一种优雅的方式来写这个吗?
(谢谢你的想法!)
Naw*_*waz 10
如果您对装饰名称没问题,那么您可以编写一个免费的功能模板:
struct Vehicle {};
struct Aircraft : Vehicle { typedef Vehicle super; };
struct Helicopter : Aircraft { typedef Aircraft super; };
template<typename T>
string getClassLineage()
{
static string lineage = string(typeid(T).name()) +" - " + getClassLineage<typename T::super>();
return lineage;
}
template<>
string getClassLineage<Vehicle>()
{
static string lineage = string(typeid(Vehicle).name());
return lineage;
}
int main() {
cout << getClassLineage<Helicopter>() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出(装饰名称):
10Helicopter - 8Aircraft - 7Vehicle
请参阅ideone:http://www.ideone.com/5PoJ0
如果你愿意,你可以剥掉装饰.但它将是特定于编译器的!这是一个使用remove_decoration
函数去除装饰的版本,然后输出变为:
直升机 - 飞机 - 车辆
顺便说一下,正如我所说,remove_decoration
函数的实现是一个特定的编译器; 另外,这可以用更正确的方式编写,因为我不知道GCC考虑的所有情况,同时修改了类名.但我希望,你得到了基本的想法.
如果您可以在每个派生类中重新定义函数,那么这是一个简单的解决方案:
struct Vehicle
{
string getClassLineage() const { return "Vehicle"; }
};
struct Aircraft : Vehicle
{
string getClassLineage() const { return Vehicle::getClassLineage()+" - Aircraft"; }
};
struct Helicopter : Aircraft
{
string getClassLineage() const { return Aircraft::getClassLineage()+" - Helicopter "; }
};
int main() {
Helicopter heli;
cout << heli.getClassLineage() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
车辆 - 飞机 - 直升机
请参阅ideone上的输出:http://www.ideone.com/Z0Tws
如果你想要一个类似递归的方法,你可以使用虚函数和显式作用域函数调用来实现:
struct vehicle {
virtual std::string lineage() const { return "vehicle"; }
};
struct aircraft : vehicle {
typedef vehicle base;
virtual std::string lineage() const { return base::lineage() + "--aircraft"; }
};
struct biplane : aircraft {
typedef aircraft base;
virtual std::string lineage() const { return base::lineage() + "--biplane"; }
};
struct nieuport17 : biplane {
typedef biplane base;
virtual std::string lineage() const { return base::lineage() + "--nieuport17"; }
};
int main() {
biplane b;
aircraft const & a = b;
std::cout << a.lineage() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它是如何工作的?当你调用v.lineage()
它是一个虚函数时,动态分派将进入它,biplane::lineage()
因为它是对象的实际类型。在该函数内部有对其父lineage()
函数的限定调用。合格的调用不使用动态调度机制,因此调用实际上会在父级执行。基本上这就是正在发生的事情:
a.lineage() -- dynamic dispatch -->
---> biplane::lineage()
\__ airplane::lineage()
\__ vehigcle::lineage()
<-- std::string("vehicle")
<-- std::string("vehicle") + "--airplane"
<-- std::string("vehicle--airplane") + "--biplane"
<--- std::string( "vehicle--airplane--biplane" )
Run Code Online (Sandbox Code Playgroud)