gpt4 book ai didi

c++ - 在容器中正确使用多态性?

转载 作者:行者123 更新时间:2023-11-28 00:02:14 25 4
gpt4 key购买 nike

在我开始处理的这段代码中,我发现了一个常见的模式,但不知怎么的,我并不适合这种模式。通常,它涉及一个枚举、一个映射、一个开关和某种类层次结构。我试图抽象出一个 MWE:

#include <iostream>
#include <map>

class Shape {
public:
virtual double SumOfInternalAngles() { throw std::exception(); }
};

class Triangle : public Shape {
public:
double SumOfInternalAngles() { return 180.0; }
};

class Rectangle : public Shape {
public:
double SumOfInternalAngles() { return 360.0; }
};

enum TeamShapes {AlicesTriangle, BobsRectangle, CarolsTriangle};

int main()
{
Triangle alicesTriangle;
Rectangle bobsRectangle;
Triangle carolsTriangle;

std::map<TeamShapes, Shape*> shapeMap;
shapeMap[TeamShapes::AlicesTriangle] = &alicesTriangle;
shapeMap[TeamShapes::BobsRectangle] = &bobsRectangle;
shapeMap[TeamShapes::CarolsTriangle] = &carolsTriangle;

for(auto it : shapeMap)
{
switch (it.first)
{
case TeamShapes::AlicesTriangle:
std::cout << it.second->SumOfInternalAngles() << std::endl;
break;

case TeamShapes::BobsRectangle:
std::cout << static_cast<Rectangle*>(it.second)->SumOfInternalAngles() << std::endl;
break;
}
}
return 0;
}

似乎有重复的信息,访问成员函数的两个版本都有缺点:第一种情况,你需要在基类中有一个虚拟成员函数,这意味着所有的派生类都“困惑”具有对他们没有真正意义的功能,例如Circle 将以函数 getCorners() 结束。在第二种情况下,我宁愿不需要强制转换,尽管我知道这是必要的。也许有人可以指出我可以为这种情况提出更好设计的方向。

我是 C++ 的新手,所以我想听听关于此类构造的“最佳实践”和“约定”是什么。也许代码没问题,我只是需要调整一下?

最佳答案

如果您使您的基类成为纯虚拟的(即使该类成为抽象类),则您不必在其中实现 SumOfInternalAngles(),因此无需抛出异常。然后 Shape 成为一个抽象接口(interface),由派生类实现,这个派生类必须实现 SumOfInternalAngles()

然后在你的 switch 语句中,你不需要强制转换,除非你想调用一个特定于派生类的方法,例如 getCorners(),它可能存在也可能不存在于所有派生类中Shape 的版本。

要做到这一点,只需将形状定义更改为

class Shape {
public:
virtual double SumOfInternalAngles() = 0;
};

并使用第一个版本的 switch case。

 case TeamShapes::AlicesTriangle:
std::cout << it.second->SumOfInternalAngles() << std::endl;
break;

case TeamShapes::BobsRectangle:
std::cout << it.second->SumOfInternalAngles() << std::endl;
break;

编辑:一些示例代码来尝试帮助说明。

#include <iostream>
#include <string>

class base
{
public:

virtual std::string AMethodThatMustBeImplemented() = 0;
virtual std::string ABaseMethod() { return std::string("base::ABaseMethod"); }
};

class A : public base
{
public:
virtual std::string AMethodThatMustBeImplemented() { return std::string("A::AMethodThatMustBeImplmented"); }
// No need to implment ABaseMethod here unless we wanted to!
};

class B : public base
{
public:
virtual std::string AMethodThatMustBeImplemented() { return std::string("B::AMethodThatMustBeImplmented"); }
virtual std::string ABaseMethod() { return std::string("B::ABaseMethod"); }
};

int main(int argc, char** argv)
{
//base obj; // can't do this since base has 'pure virtual' called AMethodThatMustBeImplemented.

A objA;
B objB;

std::cout << objA.AMethodThatMustBeImplemented() << '\n';
std::cout << objA.ABaseMethod() << '\n';
std::cout << objB.AMethodThatMustBeImplemented() << '\n';
std::cout << objB.ABaseMethod() << '\n';

base& b = static_cast<base&>(objB);
std::cout << b.ABaseMethod() << " <- notice still calling B::ABaseMethod\n";
std::cout << b.base::ABaseMethod() << " <- ah-ha now calling base::ABaseMethod\n";

}

关于c++ - 在容器中正确使用多态性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37985075/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com