我遇到的问题是多态类:动物类有一个函数“虚拟动物* get() = 0;”这个函数在狗类中定义为“speak2* get() { speak2();返回this;}”。
不久前,我在某个地方读到,以这种方式更改返回类型是合法的,但它似乎不像我预期的那样起作用:当调用get函数时,它会打印预期值,但是当我试图将返回值赋值给狗类指针时,我会得到一个无效的转换错误,当我试图调用speak2()函数时,它说它没有这样的成员。
我想要的是能够按照"barn.front()->get()->speak2();“的方式调用一些东西。在没有任何dynamic_casts或任何这样的强制转换的情况下,有什么方法可以达到类似的效果吗?
我以一种逻辑的方式命名了这些类,使其易于阅读,并在以下代码中以注释的形式添加了一些注释:
#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;
}发布于 2013-01-07 15:15:56
您的代码在不同的时间发生了两件事。首先,编译器将barn.front()的返回类型视为animal*。不管你做什么。在类型speak2()上调用成员animal*总是失败的。
您的成员get()是一个虚拟函数,使用行barn.front()->get();使用虚拟调度调用。这意味着被调用的函数只有在运行时才知道,这取决于动物的真正(所谓的动态)类型。这样你就可以改变get()对每种动物的行为。
get()的不同返回值在这里并不重要。编译器所做的类型检查(显然)是在编译时完成的,因此是针对animal::get()的。只有在直接调用静态类型dog的对象时,协变量返回类型才会有用。
在您的示例中,一种常见的方法是将类型转换为dog,如下所示
static_cast<dog*>(barn.front())->speak2();当然,如果barn.front()的实际类型不是狗,您就会烧掉它。我指的是未定义的行为--程序可能会崩溃、抛出异常或无声地继续处理损坏的数据。
在我的oppinion中,更正确的方法是将不同的操作分离到一个通用接口中,例如:
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();
}发布于 2013-01-07 14:51:09
接口编程的全部目的是使用接口类作为访问点,并依赖于实现的具体类型来符合接口。对于您来说,这意味着您应该通过指向动物的指针访问矢量中的实际动物。如果您将speak2()定义为动物类中的一个纯虚拟函数,并且使用动物*而不是狗*,那么您的程序将运行。问题仍然是,是否所有动物都有speak2()能力,但这就是设计的问题。注意,我已经将using指令放在类实现的下面,因为在库代码中使用命名空间指令并不是一个好做法。
下面是包含更改的代码:
#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;
}发布于 2013-01-07 14:47:46
使用barn->front()->get()时,您可以访问animal*指针。Speak2()不是为animal定义的,因此no member error。
https://stackoverflow.com/questions/14198124
复制相似问题