首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >返回与定义的多态函数不同的类型。

返回与定义的多态函数不同的类型。
EN

Stack Overflow用户
提问于 2013-01-07 14:42:42
回答 4查看 1.4K关注 0票数 1

我遇到的问题是多态类:动物类有一个函数“虚拟动物* get() = 0;”这个函数在狗类中定义为“speak2* get() { speak2();返回this;}”。

不久前,我在某个地方读到,以这种方式更改返回类型是合法的,但它似乎不像我预期的那样起作用:当调用get函数时,它会打印预期值,但是当我试图将返回值赋值给狗类指针时,我会得到一个无效的转换错误,当我试图调用speak2()函数时,它说它没有这样的成员。

我想要的是能够按照"barn.front()->get()->speak2();“的方式调用一些东西。在没有任何dynamic_casts或任何这样的强制转换的情况下,有什么方法可以达到类似的效果吗?

我以一种逻辑的方式命名了这些类,使其易于阅读,并在以下代码中以注释的形式添加了一些注释:

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

class animal
{
public:
    virtual ~animal() {}
    virtual void speak1() = 0;
    virtual animal* get() = 0;
};

class dog : public animal
{
public:
    void speak1() { cout << "print-speak1!"; }
    void speak2() { cout << "print-speak2!"; }
    dog* get() { speak2(); return this; }
};

int main()
{
    vector<animal*> barn;

    barn.push_back(new dog());

    barn.front()->speak1();                // prints "print-speak1!"
    barn.front()->get();                   // prints "print-speak2!"

    barn.front()->get()->speak2();
    // error: 'class animal' has no member named 'speak2'
    // but then why does "barn.front()->get();" print "print-speak2!"?

    dog* dogptr = barn.front()->get();
    // error: invalid conversion from 'animal*' to 'dog*' [-fpermissive]

    dogptr->speak2();
    // for the sake of -Werror=unused-variable

    for(vector<animal*>::iterator i = barn.begin(); i != barn.end(); ++i)
    {
        delete *i;
    }
    barn.clear();

    return 0;
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-01-07 15:15:56

您的代码在不同的时间发生了两件事。首先,编译器将barn.front()的返回类型视为animal*。不管你做什么。在类型speak2()上调用成员animal*总是失败的。

您的成员get()是一个虚拟函数,使用行barn.front()->get();使用虚拟调度调用。这意味着被调用的函数只有在运行时才知道,这取决于动物的真正(所谓的动态)类型。这样你就可以改变get()对每种动物的行为。

get()的不同返回值在这里并不重要。编译器所做的类型检查(显然)是在编译时完成的,因此是针对animal::get()的。只有在直接调用静态类型dog的对象时,协变量返回类型才会有用。

在您的示例中,一种常见的方法是将类型转换为dog,如下所示

代码语言:javascript
复制
static_cast<dog*>(barn.front())->speak2();

当然,如果barn.front()的实际类型不是狗,您就会烧掉它。我指的是未定义的行为--程序可能会崩溃、抛出异常或无声地继续处理损坏的数据。

在我的oppinion中,更正确的方法是将不同的操作分离到一个通用接口中,例如:

代码语言:javascript
复制
class animal
{
public:
    virtual ~animal() {}
    virtual void makeSound() = 0;
};

class dog : public animal
{
public:
    void bark() { cout << "hoof"; }
    void makeSound() { bark(); }
};

class cat : public animal
{
public:
    void meow() { cout << "meow"; }
    void makeSound() { meow(); }
};

int main()
{
    vector<animal*> barn;
    barn.push_back(new dog());
    barn.push_back(new cat());
    barn.front()->makeSound();
    barn[1]->makeSound();
}
票数 1
EN

Stack Overflow用户

发布于 2013-01-07 14:51:09

接口编程的全部目的是使用接口类作为访问点,并依赖于实现的具体类型来符合接口。对于您来说,这意味着您应该通过指向动物的指针访问矢量中的实际动物。如果您将speak2()定义为动物类中的一个纯虚拟函数,并且使用动物*而不是狗*,那么您的程序将运行。问题仍然是,是否所有动物都有speak2()能力,但这就是设计的问题。注意,我已经将using指令放在类实现的下面,因为在库代码中使用命名空间指令并不是一个好做法。

下面是包含更改的代码:

代码语言:javascript
复制
#include <iostream>
#include <vector>

class animal
{
public:
    virtual ~animal() {}
    virtual void speak1() = 0;
    virtual void speak2() = 0;
    virtual animal* get() = 0;
};

class dog : public animal
{
public:
    void speak1() { std::cout << "print-speak1!" << std::endl; }
    void speak2() { std::cout << "print-speak2!" << std::endl; }
    dog* get() { speak2(); return this; }
};

using namespace std;

int main()
{
    vector<animal*> barn;

    barn.push_back(new dog());

    barn.front()->speak1();                // prints "print-speak1!"
    barn.front()->get();                   // prints "print-speak2!"

    barn.front()->get()->speak2();
    // error: 'class animal' has no member named 'speak2'
    // but then why does "barn.front()->get();" print "print-speak2!"?

    animal* dogptr = barn.front()->get();
    // error: invalid conversion from 'animal*' to 'dog*' [-fpermissive]

    dogptr->speak2();
    // for the sake of -Werror=unused-variable

    for(vector<animal*>::iterator i = barn.begin(); i != barn.end(); ++i)
    {
        delete *i;
    }
    barn.clear();

    return 0;
}
票数 1
EN

Stack Overflow用户

发布于 2013-01-07 14:47:46

使用barn->front()->get()时,您可以访问animal*指针。Speak2()不是为animal定义的,因此no member error

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14198124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档