问题描述
我有一个用作接口的基类(如果我正确使用了这个词)。这个想法是基类有一些派生类实现基类的一个虚函数。然后我还需要另一个扩展基类的类(我们称之为扩展基类)。我想要的是我可以将从基派生的类存储到扩展基指针中。
MWE:
class Base {
public:
virtual ~Base();
virtual double value();
}
class Derived : public Base{
public:
double value() override {return 5;}
}
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase ();
virtual double value2(){return 10;}
}
int main() {
ExtendedBase * object;
object = new Derived();
std::cout << object->value(); //should give implementation in Derived,i.e. 5
std::cout << object->value2(); //should give implementation in ExtendedBase,i.e. 10
delete object;
return 0;
}
使用这个 MWE,我在主文件的第二行得到一个编译错误。 error: cannot convert 'Derived*' to 'ExtendedBase*' in assignment object = new Derived();
。我的一部分理解为什么它不起作用(虽然我无法解释),但我想知道我是否可以通过其他方式获得所需的行为。
P.S.2 我知道不建议使用这样的原始指针。将来我会改用智能指针,但我认为这个简单的例子不需要
解决方法
当您为指针分配地址时,这意味着您应该能够通过指针访问指针指向的类型的所有成员。
例如,
class B {};
class D : B {};
B *p = new D();
现在通过p,至少可以访问派生类的基部分的所有成员。
但是在您的代码中,
ExtendedBase * object;
object = new Derived();
对象应该能够访问派生类的 ExtendedBase 部分的所有成员。但是派生类怎么可能不是从 ExtendeBase 派生的。所以编译器抛出错误。
您需要对代码进行一些更改才能工作。
- 要将基类作为接口(抽象类),您需要在 至少一个成员函数是纯虚函数。
- 如果你想通过以下方式访问ExtendedBase的成员函数 基指针,你应该在你的 扩展基础。
以下是变化。
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {};
virtual double value() = 0;
};
class Derived : public Base{
public:
~Derived() {};
double value() {
return 5;
}
};
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase () {};
double value()
{
return 10;
}
};
int main() {
Base *p = new Derived();
std::cout << p->value() << std::endl;
delete p;
Base *p1 = new ExtendedBase();
std::cout << p1->value() << std::endl;
delete p1;
return 0;
}
,
ExtendedBase
和 Derived
均源自 Base
。如果要使用 ExtendedBase*
指针指向 Derived
对象,则需要从 Derived
派生 ExtendedBase
。
换个例子,
class Feline{
virtual void run();
}
class Housecat : Feline{
void run() {}
}
class BigCat : Feline{
virtual void run();
virtual void roar();
}
此处的 Feline
、Housecat
和 BigCat
类似于 Base
、Derived
和 ExtendedBase
。 BigCat
和 Housecat
都是 Feline
,但由于 Housecat
不是 BigCat
,您不能使用 BigCat*
指针指向Housecat
。
从语言架构师的角度来看,这是理想的行为。 例如,如果你有
class Ship
{
public:
virtual void move() = 0;
}
class Steamboat : public Ship
{
public:
virtual void move() override { ... }
}
class Sailboat : public Ship
{
public:
virtual void move() override { ... }
virtual void setSails() { ... }
}
现在,您不希望汽船突然变成帆船,因此:
Steamboat* tootoo = new Sailboat;
无效。 这就是您的代码无法工作的原因。从概念上讲。 因此无法快速修复,因为您的概念不是很清楚。