我有一个下面的抽象类
class A {
public:
virtual void foo(A* a) = 0;
}
以及从该类继承的几个类。例如
class B : public A {
public:
void foo(A* a); // implementation in a separete file
}
但是,我只希望类B
接受自己作为foo
中的参数
void foo(B* b);
是否可以在C ++中做到这一点?
我考虑过模板,但是语法允许太多的灵活性。可以写class B: public A<B>
,但是我想用class B: public A<C>
编译器错误。
-编辑-
似乎我对抽象类的使用是不合理的。让我澄清一下我的情况。
我在单独的函数中利用A
的多态行为。除此之外,我想定义一个函数,该函数接受相同类型的参数,例如上面的参数。我正在尝试编写一个函数,该函数定义派生类的两个对象之间的距离。距离仅在同一类(b1
和b2
或c1
和c2
,而不是b1
和c2
的对象之间定义) 。我也想以一种通用的方式来访问这个距离函数。
-编辑2-
Cássio显示了为什么无法执行基于编译器的检查。 zar的解决方案通过运行时错误检查为代码增加了一些结构。
答案 0 :(得分:1)
那不是virtual
的目的。
virtual
用于启用多态行为。基本上,要启用此功能:
struct A {virtual void foo()=0;};
// Two different "behaviors" for the same "A"
struct B {void foo() override{}};
struct C {void foo() override{}};
// forgive the leak, this is just to prove a point.
A* b = new B();
A* c = new C();
b->foo(); // Will call B::foo, even though this is a pointer to "A"
c->foo(); // Will call C::foo, even though this is a pointer to "A"
您尝试使用它的方式,失去了这一好处,而您却一无所获地获得了虚拟函数的性能优势。实例化一个没有实现某些纯虚函数的类是一个错误,实际上只是为了防止格式错误的程序。
如果要确保B
实现某些接口,只需在某个地方使用该接口即可。如果B
未实现,则会出现您要查找的编译器错误:
class B {};
template<typename T> void call_foo(T* v1, T* v2) {
v1->foo(&v2);
}
B b1;
B b2;
b1.foo(&b2); // error
call_foo(&b1, &b2); // error
然后,要消除错误,您只需实现函数即可。无需virtual
:
class B {
void foo(B*) {/*do something*/}
};
B b1;
B b2;
b1.foo(&b2); // ok
call_foo(&b1, &b2); // ok
想象一下以下情况:
struct A {virtual void foo(A*)=0;};
// Imagine if the language allowed this:
struct B {void foo(B*) override{}};
struct C {void foo(C*) override{}};
// (...)
// I create a vector of objects, and insert three of them in this vector.
std::vector<A*> objects;
// Note that foo is well-defined only for the first two.
objects.push_back(new B();)
objects.push_back(new B();)
objects.push_back(new C();)
// Then I shuffle the vector
std::shuffle(objects.begin(), objects.end());
// At least one of these three lines should give a compiler error.
// Which one(s)?
objects[0]->foo(objects[1]);
objects[0]->foo(objects[2]);
objects[1]->foo(objects[2]);
虚拟函数是一种运行时机制。您将必须在运行时检查类型。 zar's answer已经很好地涵盖了这一点,因此我将不赘述。总结一下:只需将dynamic_cast
插入所需的类型,如果强制转换返回nullptr
,则您输入的类型错误。然后,您可以引发异常或打印一些诊断消息。
答案 1 :(得分:1)
我了解您的问题更多是关于语法的。您所拥有的是正确的,只需传递一个B类型的对象即可。该定义仍然会说A,但是很高兴采用派生类。为此,您不需要任何特殊的定义。
class A {
public:
virtual void foo(A* a) = 0;
};
class B : public A {
public:
void foo(A* a)
{
if (dynamic_cast<B*> (a) == NULL)
std::cout << "wrong type, expecting type B\r\n";
}
};
class C : public A {
public:
void foo(A* a)
{
if (dynamic_cast<C*> (a) == NULL)
std::cout << "wrong type, expecting type C\r\n";
}
};
int main()
{
B * b1 = new B;
B * b2 = new B;
C * c1 = new C;
C * c2 = new C;
b2->foo(c1); // bad
c1->foo(b1); // bad
b2->foo(b1); // good
delete b1;
delete b2;
delete c1;
delete c2;
}
另请参见dynamic_cast。