我有时会注意到计算机崩溃的程序出现错误:"纯虚函数调用".
当无法创建抽象类的对象时,这些程序如何编译?
我见过的几乎所有C++资源都讨论过这种事情告诉我,我应该更喜欢使用RTTI(运行时类型识别)的多态方法.总的来说,我认真对待这种建议,并会尝试理解其基本原理 - 毕竟,C++是一个强大的野兽,并且很难全面理解.然而,对于这个特殊的问题,我正在画一个空白,并希望看到互联网可以提供什么样的建议.首先,让我总结一下到目前为止我所学到的内容,列出引用为什么RTTI被"认为有害"的常见原因:
我真的不买这个论点.这就像是说我不应该使用C++ 14的功能,因为有些编译器不支持它.然而,没有人会阻止我使用C++ 14功能.大多数项目将对他们正在使用的编译器以及它的配置方式产生影响.甚至引用gcc手册页:
-fno-rtti禁止使用虚拟函数生成有关每个类的信息,以供C++运行时类型标识功能(dynamic_cast和typeid)使用.如果您不使用该语言的那些部分,则可以使用此标志来节省一些空间.请注意,异常处理使用相同的信息,但G ++会根据需要生成它.dynamic_cast运算符仍可用于不需要运行时类型信息的强制类型转换,即强制转换为"void*"或转换为明确的基类.
这告诉我的是,如果我不使用RTTI,我可以禁用它.这就像说,如果你没有使用Boost,你就不必链接到它.我没有计划有人正在编译的情况-fno-rtti.此外,在这种情况下,编译器将失败并且清晰.
每当我想要使用RTTI时,这意味着我需要访问我班级的某种类型信息或特征.如果我实现了一个不使用RTTI的解决方案,这通常意味着我将不得不在我的类中添加一些字段来存储这些信息,因此内存参数有点无效(我将进一步说明这一点).
事实上,dynamic_cast可能很慢.但是,通常有办法避免使用速度危急情况.而且我没有看到替代方案.这个SO答案建议使用在基类中定义的枚举来存储类型.这只有在您了解所有派生类时才有效.这是一个非常大的"如果"!
从这个答案来看,RTTI的成本似乎也不清楚.不同的人衡量不同的东西.
这是我认真对待的建议.在这种情况下,我根本无法提出覆盖我的RTTI用例的良好的非RTTI解决方案.让我举一个例子:
假设我正在编写一个库来处理某种对象的图形.我想允许用户在使用我的库时生成自己的类型(因此enum方法不可用).我的节点有一个基类:
class node_base
{
public:
node_base();
virtual ~node_base();
std::vector< std::shared_ptr<node_base> > get_adjacent_nodes();
};
Run Code Online (Sandbox Code Playgroud)
现在,我的节点可以是不同类型的.这些怎么样:
class red_node : virtual public node_base
{
public:
red_node();
virtual ~red_node();
void get_redness();
};
class yellow_node : virtual public node_base
{
public:
yellow_node();
virtual ~yellow_node();
void set_yellowness(int);
};
Run Code Online (Sandbox Code Playgroud)
见鬼,为什么不是其中之一:
class orange_node : public red_node, public yellow_node
{
public:
orange_node();
virtual ~orange_node();
void …Run Code Online (Sandbox Code Playgroud) 我正在研究多线程应用程序,我想使用GDB进行调试.
问题是,我的一个线程一直在消息中消失:
pure virtual method called
terminate called without an active exception
Abort
Run Code Online (Sandbox Code Playgroud)
我知道该消息的原因,但我不知道我的帖子在哪里发生.回溯真的很有帮助.
当我在GDB中运行我的应用程序时,每次线程暂停或恢复时它都会暂停.我希望我的应用程序继续正常运行,直到其中一个线程因该异常而死亡,此时所有内容都应该暂停,以便我可以获得回溯.
具有一系列"instanceof"操作被认为是"代码味道".标准答案是"使用多态".在这种情况下我该怎么做?
基类有许多子类; 没有一个在我的控制之下.类似的情况是Java类Integer,Double,BigDecimal等.
if (obj instanceof Integer) {NumberStuff.handle((Integer)obj);}
else if (obj instanceof BigDecimal) {BigDecimalStuff.handle((BigDecimal)obj);}
else if (obj instanceof Double) {DoubleStuff.handle((Double)obj);}
Run Code Online (Sandbox Code Playgroud)
我确实可以控制NumberStuff等等.
我不想在几行代码中使用多行代码.(有时我将一个HashMap映射到一个IntegerStuff的实例,将BigDecimal.class映射到一个BigDecimalStuff的实例等等.但是今天我想要一些更简单的东西.)
我想要像这样简单的东西:
public static handle(Integer num) { ... }
public static handle(BigDecimal num) { ... }
Run Code Online (Sandbox Code Playgroud)
但是Java不会那样工作.
我想在格式化时使用静态方法.我正在格式化的东西是复合的,其中Thing1可以包含一个数组Thing2s和Thing2可以包含一个Thing1s数组.当我实现这样的格式化程序时,我遇到了问题:
class Thing1Formatter {
private static Thing2Formatter thing2Formatter = new Thing2Formatter();
public format(Thing thing) {
thing2Formatter.format(thing.innerThing2);
}
}
class Thing2Formatter {
private static Thing1Formatter thing1Formatter = new Thing1Formatter();
public format(Thing2 thing) {
thing1Formatter.format(thing.innerThing1);
}
}
Run Code Online (Sandbox Code Playgroud)
是的,我知道HashMap和更多代码也可以修复它.但相比之下,"instanceof"似乎更具可读性和可维护性.有什么简单但不臭吗?
注释已添加5/10/2010:
事实证明,将来可能会添加新的子类,而我现有的代码必须优雅地处理它们.在这种情况下,类上的HashMap不起作用,因为找不到类.一系列if语句,从最具体的开始到以最一般的结尾,可能是最好的:
if (obj instanceof SubClass1) …Run Code Online (Sandbox Code Playgroud) java reflection polymorphism instanceof chain-of-responsibility
我在使用Gson反序列化json字符串时遇到问题.我收到一系列命令.该命令可以是start,stop,其他一些命令.当然我有多态,并且start/stop命令继承自命令.
如何使用gson将其序列化回正确的命令对象?
似乎我只得到基类型,即声明的类型,而不是运行时类型.
我看过其他定义和解释,但没有一个能让我满意.我想知道是否有人可以在不使用任何代码或示例的情况下在最多两个句子中定义多态性.我不想听到'所以你有一个人/汽车/开罐器......'或者这个词是如何衍生出来的(没有人会对你知道poly和morph意味着什么感到印象深刻).如果你非常了解多态性是什么并且掌握了良好的英语能力,那么你应该能够在一个简短的,虽然密集的定义中回答这个问题.如果你的定义准确地定义了多态,但是如此密集以至于需要一些读取,那么这正是我正在寻找的.
为什么只有两句话?因为定义简短而且聪明.解释很长,包含示例和代码.在这里查看解释(这些页面上的答案对我的问题不满意):
我为什么问这个问题?因为我被问到同样的问题而且我发现我无法得出令人满意的定义(根据我的标准,这是非常高的).我想看看这个网站上是否有任何伟大的思想能够做到这一点.
如果你真的不能完成两句话的要求(这是一个难以定义的主题),那么如果你继续下去就没关系.我们的想法是有一个定义,它实际上定义了什么是多态,并没有解释它的作用或如何使用它(得到差异?).
我已经阅读了一些我可以在互联网上找到的关于多态性的文章.但我认为我无法理解它的含义及其重要性.大多数文章没有说明为什么它很重要以及如何在OOP中实现多态行为(当然在JavaScript中).
我无法提供任何代码示例,因为我还没有想到如何实现它,所以我的问题如下:
我有这个例子.但是很容易理解这段代码会产生什么结果.它没有给出关于多态性本身的任何清晰的想法.
function Person(age, weight) {
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo.";
}
}
function Employee(age, weight, salary) {
this.salary = salary;
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" …Run Code Online (Sandbox Code Playgroud) javascript oop polymorphism functional-programming parametric-polymorphism
我有一个对象层次结构,我需要通过RESTful API公开,我不确定我的URL应该如何构建以及它们应该返回什么.我找不到任何最佳做法.
假设我有继承动物的狗和猫.我需要对狗和猫进行CRUD操作; 我也希望能够对动物进行一般操作.
我的第一个想法是做这样的事情:
GET /animals # get all animals
POST /animals # create a dog or cat
GET /animals/123 # get animal 123
Run Code Online (Sandbox Code Playgroud)
问题是/ animals集合现在"不一致",因为它可以返回并获取不具有完全相同结构的对象(狗和猫).将集合返回具有不同属性的对象,它被认为是"RESTful"吗?
另一个解决方案是为每个具体类型创建一个URL,如下所示:
GET /dogs # get all dogs
POST /dogs # create a dog
GET /dogs/123 # get dog 123
GET /cats # get all cats
POST /cats # create a cat
GET /cats/123 # get cat 123
Run Code Online (Sandbox Code Playgroud)
但现在狗和猫之间的关系就失去了.如果想要检索所有动物,必须查询狗和猫的资源.每个新的动物子类型的URL数量也会增加.
另一个建议是通过添加以下内容来扩充第二个解决方案:
GET /animals # get common attributes of all animals
Run Code Online (Sandbox Code Playgroud)
在这种情况下,返回的动物将仅包含所有动物共有的属性,丢弃特定于狗的属性和特定于猫的属性.这允许检索所有动物,尽管细节较少.每个返回的对象都可以包含指向详细的具体版本的链接.
有什么意见或建议吗?
考虑:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void show() { cout<<" In Base \n"; }
};
class Derived: public Base
{
public:
void show() { cout<<"In Derived \n"; }
};
int main(void)
{
Base *bp = new Derived;
bp->show(); // RUN-TIME POLYMORPHISM
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么这段代码会导致运行时多态性,为什么不能在编译时解决它?
其他潜在贡献者请注意:请不要犹豫,使用抽象或数学符号来表达您的观点.如果我发现你的答案不清楚,我会要求澄清,但你可以随意以舒适的方式表达自己.
要明确:我不是在寻找"安全" head,也不是head特别有意义的选择.问题的关键在于讨论head和讨论,并head'提供了背景.
我几个月来一直在用Haskell进行攻击(直到它已经成为我的主要语言),但我对一些更先进的概念以及语言哲学的细节都不了解(尽管我非常愿意学习).那么我的问题不是技术问题(除非它是,我只是没有意识到),因为它是一种哲学.
对于这个例子,我说的是head.
我想你会知道,
Prelude> head []
*** Exception: Prelude.head: empty list
Run Code Online (Sandbox Code Playgroud)
这是从head :: [a] -> a.很公平.显然,一个人不能返回(挥手)没有类型的元素.但与此同时,定义它很简单(如果不是微不足道的话)
head' :: [a] -> Maybe a
head' [] = Nothing
head' (x:xs) = Just x
Run Code Online (Sandbox Code Playgroud)
我见过一些这方面的讨论很少在这里的某些语句的注释部分.值得注意的是,一位Alex Stangl说
"有充分的理由不让一切都"安全",并在违反前提条件时抛出异常.
我不一定质疑这个断言,但我很好奇这些"好理由"是什么.
此外,保罗约翰逊说,
'例如你可以定义"safeHead :: [a] - >也许是",但现在不是处理空列表或证明它不会发生,你必须处理"没什么"或证明它不会发生".
我从该评论中读到的语气表明,这是难度/复杂度/事物的显着增加,但我不确定我是否掌握了他在那里推出的内容.
一位Steven Pruzina说(2011年,不低于),
"有一个更深层次的原因,例如'head'不能防止崩溃.要进行多态而处理空列表,'head'必须始终返回任何特定空列表中不存在的类型变量.它将是Delphic如果Haskell能做到这一点......".
允许空列表处理会导致多态性丢失吗?如果是这样,怎么样,为什么?是否有特殊情况会使这一点变得明显?本节由@Russell O'Connor充分回答.当然,任何进一步的想法都会受到赞赏.
我会根据清晰度和建议来编辑这个.您可以提供的任何想法,论文等都将非常感激.
polymorphism ×10
c++ ×4
java ×2
oop ×2
api ×1
debugging ×1
gdb ×1
gson ×1
haskell ×1
inheritance ×1
instanceof ×1
javascript ×1
json ×1
multicore ×1
pure-virtual ×1
reflection ×1
rest ×1
rtti ×1
terminology ×1