如何从接收指向基类的指针的实例的成员函数中访问派生类的数据?我有:
class Base{
public:
virtual void compare(Base*)=0;
};
class A: public Base{
int x;
public:
A();
void compare(Base*);
};
class B: public Base{
char c;
public:
void compare(Base*);
};
A::A(){
x = 1;
};
void A::compare(Base *p){
cout<< "A's x is " << x << "\n";
cout<< "Argument's x is " << p->x;
};
void B::compare(Base* p){
cout<< "B's compare() is running\n";
};
int main(const int argc, const char *argv[]){
A a1 = A();
A a2 = A();
B b = B();
a1.compare(&a2);
}
由于Base
没有数据成员x
,因此无效。在我写这篇文章时,我发现通过指向Base接口类的指针来访问派生类的数据成员并不是一个好主意。
在我的问题中,我需要将不同的派生类与Base
类提供的相同接口进行比较。 Base
的接口必须包含compare(Base*)
成员函数。实例的比较方式可能因派生类别而异。显然,比较逻辑应该在这些类的成员函数中编码。我该如何实施这个模型?
答案 0 :(得分:4)
除非您的派生类共享一些您想要通过基类访问的常用数据,否则没有简单的解决方案。
例如,除非您的派生类数量非常少,否则在每个派生类中动态转换都是多余的,缓慢且容易出错的。
更大类型层次结构的一个解决方案是double dispatch。
答案 1 :(得分:1)
您可以使用dynamic_cast
将基指针强制转换为其中一种派生类型。请务必正确处理dynamic_cast无法转换指针的情况。
我应该补充一点,这是一种有臭味的方法。如果对象真的具有可比性,那么它们在基类级别上应具有可比性。
答案 2 :(得分:1)
你可能会跛着回家,这取决于你的对象层次结构:
bool A::compare(Base *p){
A *pa = dynamic_cast<A*>(p);
if (!pa) return false;
return x == pa->x;
};
实际上,实施多态比较存在严重困难。问题是如果a是A的实例,而c是A的某个派生类C的实例,那么使用这种技术你很容易就会得到a.compare(c)为true,但是c.compare (a)是假的。
你可能会更好:
typeid
,如果不相等则返回false,如果是,则调用其中两个对象的虚拟comparisonImpl函数。然后A :: comparisonImpl知道它的参数是A的一个实例,并且可以static_cast it:
class Base {
public:
bool compare(Base *p) {
if (typeid(*this) != typeid(*p)) return false;
return compareImpl(p);
}
private:
virtual bool compareImpl(Base *p) = 0;
};
class A : public Base {
int x;
private:
bool compareImpl(Base *p) {
return x == static_cast<A*>(p)->x;
}
};
答案 3 :(得分:1)
的dynamic_cast。
struct Base
{
virtual bool compare(const Base*) = 0;
};
struct A : Base
{
A()
{
x = 1;
}
virtual bool compare(const Base* other)
{
const A* rhs(dynamic_cast<const A*>(other));
if(other == NULL) { return false; }
return x == rhs->x;
}
private:
int x;
};
struct B : Base
{
virtual bool compare(const Base* other)
{
const B* rhs(dynamic_cast<const B*>(other));
if(other == NULL) { return false; }
return c == rhs->c;
}
private:
char c;
};
答案 4 :(得分:1)
我不得不在前一段时间里一直在努力。在我的情况下,具体要求要求两个元素只有当它们实际上具有相同的确切类型时才会相等。也就是说,在比较苹果和苹果时,你只想要一个积极的匹配,但是在最大的衍生水平(金苹果到金苹果,而不是皇家嘎拉苹果。)
class base {
public:
virtual bool compare( base const & rhs ) = 0;
};
class derived : public base {
public:
virtual bool compare( base const & rhs ) {
if ( typeid(*this) != typeid(rhs) ) return false;
return *this == static_cast<derived const &>(rhs);
}
};
bool operator==( derived const & lhs, derived const & rhs );
请注意,我们最终使用typeid
+ static_cast
代替更常见的动态强制转换习惯用法,以强制两种类型完全相同。如果我们使用dynamic_cast
那么对称可能会破坏并且:
class rederived : public derived {
public:
virtual bool compare( base const & rhs ) {
rederived const * p = dynamic_cast<rederived const *>(&rhs);
return p && *this == *p;
}
};
void test() {
derived d;
rederived rd;
d.compare( rd ); // compare if derived subobject is equal, possibly true
rd.compare( d ); // always false, d cannot be dyncamically casted to rederived
}
这又是因为我们的特定约束要求两个对象具有完全相同的类型。如果您只想检查它们是否在层次结构的一个级别中是“兼容的”(这本身就是一个非对称操作,因为左侧确定了您希望在哪个层次上执行比较)。
答案 5 :(得分:0)
这个怎么样?
int main(const int argc, const char *argv[]){
Base a1 = new A();
Base a2 = new A();
Base b = new B();
a1.compare(&a2); }