我想创建子类对象,该子类对象将与其他子类对象发生不同的反应(类可以欢迎其他类,但不是全部) 该代码的原理是从访客设计模式派生的:
class A
{
public :
virtual bool isWelcoming(const A* other) const =0;
virtual bool isWelcomable(const A* other) const =0;
};
class C;
class B: public A
{
public:
virtual bool isWelcoming(const A* other) const
{
return other->isWelcomable(this);
}
bool isWelcomable(const A* other) const
{
return false;
}
bool isWelcomable(const B* other) const
{
return true;
}
bool isWelcomable(const C* other) const
{
return false;
}
};
class C: public A
{
public:
virtual bool isWelcoming(const A* other) const
{
return other->isWelcomable(this);
}
bool isWelcomable(const A* other) const
{
return false;
}
bool isWelcomable(const B* other) const
{
return true;
}
bool isWelcomable(const C* other) const
{
return true;
}
};
但是当我这样做
A *b1=new B;
A *b2=new B;
A *c=new C;
std::cout<<b1->isWelcoming(b2); //--> return false but I want true;
std::cout<<c->isWelcoming(b1); //--> return false OK;
std::cout<<b1->isWelcoming(c); //--> return false but I want true;
总是调用isWelcomable(const A * other)函数,而不是重载函数isWelcomable(const B * other)或isWelcomable(const C * other)。
这是正常的,因为A :: isWelcomable(其他常量B *)和A :: isWelcomable(其他常量C *)不存在……我不希望它们存在。
是否可以调用isWelcomable(其他B常量)或isWelcomable(其他C *常量)函数?
使用dynamic_cast但不是很干净吗?像这样:
class C;
class B: public A
{
public:
virtual bool isWelcoming(const A* other) const
{
return other->isWelcomable(this);
}
bool isWelcomable(const A* other) const
{
const B* b=dynamic_cast<B*>(A);
if (b)
return isWelcomable(b);
const C* c=dynamic_cast<C*>(A);
if (c)
return isWelcomable(c);
return false;
}
bool isWelcomable(const B* other) const
{
return true;
}
bool isWelcomable(const C* other) const
{
return false;
}
};
class C: public A
{
public:
virtual bool isWelcoming(const A* other) const
{
return other->isWelcomable(this);
}
bool isWelcomable(const A* other) const
{
const B* b=dynamic_cast<B*>(A);
if (b)
return isWelcomable(b);
const C* c=dynamic_cast<C*>(A);
if (c)
return isWelcomable(c);
return false;
}
bool isWelcomable(const B* other) const
{
return true;
}
bool isWelcomable(const C* other) const
{
return true;
}
};
感谢您的帮助。
UPDATE: 使用dynamic_cast的解决方案看上去有点像非循环访问者(感谢TavianBarnes)可以做我想要的,但是使用了不推荐的dynamic_cast。此外,此解决方案违反了Liskov替代原则。
我曾经考虑过像Kai Guther建议的那样使用getType(),但使用字符串代替一个枚举,但是此解决方案也违反了Liskov替代原理,而且在我看来,还超出了“ dynamic_cast”解决方案。
因此,我认为没有解决方案不违反该原则,因此我选择第一个解决方案是因为我发现它更优雅,功能也不必很快(只需一个操作即可响应)用户操作),并且该应用程序并非用于嵌入式系统。
答案 0 :(得分:3)
问题是您将重载和重载混合在一起。
在B
类中,您有isWelcomable
函数的三个重载,但是其中只有一个会覆盖A::isWelcomable
功能:
bool isWelcomable(const A* other) const;
这就是other->isWelcomable(this)
将要调用的函数。
我建议您养成在多态时使用override
特殊关键字的习惯,以确保您定义的函数确实覆盖了父类函数:
bool isWelcomable(const A* other) const override; // Correct
bool isWelcomable(const B* other) const override; // Incorrect, compiler error
并且如前所述,B::isWelcoming
函数不会返回任何内容,即使已声明这样做。当然,这将导致undefined behavior确实使所有关于行为的猜测都没有根据。
答案 1 :(得分:0)
有一些错别字:缺少';'在课程结束时。
然后您错过了virtual bool isWelcomable(const A* other) const =0;
和B*
类型的C*
重载丢失的情况。
然后您错过了从调用的函数中返回值的方法:return other->isWelcomable(this);
为什么还要将virtual bool isWelcoming(const A* other) const
定义为虚拟的?没必要!
一般提示:如果要覆盖虚拟功能,请使用override
。在您的情况下,如果您使用编译器,则会发出错误消息!
始终启用所有警告。然后在想知道运行时结果之前捕获丢失的return语句。
完整的固定代码:
class A;
class B;
class C;
class A
{
public :
virtual bool isWelcoming(const A* other) const =0;
virtual bool isWelcomable(const A* other) const =0;
virtual bool isWelcomable(const B* other) const =0;
virtual bool isWelcomable(const C* other) const =0;
};
class B: public A
{
public:
bool isWelcoming(const A* other) const { return other->isWelcomable(this); }
bool isWelcomable(const A* other) const override { return false; }
bool isWelcomable(const B* other) const override { return true; }
bool isWelcomable(const C* other) const override { return false; }
};
class C: public A
{
public:
bool isWelcoming(const A* other) const { return other->isWelcomable(this); }
bool isWelcomable(const A* other) const override { return false; }
bool isWelcomable(const B* other) const override { return true; }
bool isWelcomable(const C* other) const override { return true; }
};
int main()
{
A *b1=new B;
A *b2=new B;
A *c=new C;
std::cout<< b1->isWelcoming(b2); //--> return false but I want true;
std::cout<< c ->isWelcoming(b1); //--> return false OK;
std::cout<< b1->isWelcoming(c); //--> return false but I want true;
}
答案 2 :(得分:0)
您传递给isWelcoming
的基类指针不能用于调用函数
bool isWelcomable(const B* other) const;
bool isWelcomable(const C* other) const;
由于A
没有具有该签名的成员。虽然可以用派生类型替换虚拟函数的返回类型,但这不适用于参数。
要获得所需的行为,A
每个派生类型都需要一个成员函数isWelcomable
class A{
public :
virtual bool isWelcoming(const A* other) const =0;
virtual bool isWelcomable(const A* other) const =0;
virtual bool isWelcomable(const B* other) const =0;
virtual bool isWelcomable(const C* other) const =0;
}
更新
如果您不希望A
引用派生类,则也可以将isWelcomable
函数换成getType
函数
// enum for convenience
enum AType{a,b,c};
class A{
public :
virtual bool isWelcoming(const A* other) const =0;
// tell which derived type you are
virtual AType getType() const {return a;};
};
class B: public A{
public:
virtual bool isWelcoming(const A* other) const
{
// decide based on what type other points to
switch(other->getType()){
case(a):
return false;
case(b):
return true;
case(c):
return true;
}
}
AType getType() const {return b;}
};
class C: public A{
public:
virtual bool isWelcoming(const A* other) const
{
switch(other->getType()){
case(a):
return false;
case(b):
return false;
case(c):
return true;
}
}
AType getType() const {return c;}
};
请注意,这会将有关B
是否欢迎C
等信息从访客移到主机,因此B
现在必须知道它欢迎什么,而不是谁欢迎。
它也不是一个非常优雅的解决方案,实际上,派生类的列表现在已从A
移至AType
。由于每个派生类都需要能够根据类型对彼此派生类做出反应,因此如果没有这样的列表,就无法解决此问题。