尽管派生 class 中有定义,但基 class 中的方法不可见;多态性和使用 `virtual` 关键字
Method nonvisibility in base class despite definition in derived class; polymorphism and using `virtual` keyword
#include <iostream>
class A {
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() { return foo; }
};
class C {
private:
A baz;
public:
C(A faz) { baz = faz; }
A get() { return baz; }
};
int main(void) {
C boo(B(1));
std::cout << boo.get().method() << std::endl;
return 0;
}
我有一个基础 class A
,其中 B
是 class 的派生。 Class C
采用 A
但我已经通过派生的 class (B
) 代替它。没有警告或错误将 B
传递给 C
,但我希望在上述情况下具有 method()
的方法可见性。
我对 virtual
不是很熟悉,但我确实尝试将 virtual int method() = 0;
添加到 A
,这会导致更多错误。
考虑我是否要添加第二个派生的 class:
class D : public A {
public:
D(int bar) { foo = bar; }
int method() { return foo+1; }
};
我希望 C
能够接受 B
或 D
我最好的假设是接受 A
并让它处理它.
如何以这种方式正确使用多态性?
预期输出如下:
int main(void) {
C boo(B(1));
C boz(D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
将是:
1
3
如果您需要使用基础 class 类型 A 调用类型 B 的方法 (),则必须在 运行时 期间进行查找。查找是回答以下问题所必需的:应该调用哪个方法? - 与当前行中的类型相对应的那个?还是继承层次结构中的其他方法?” 如果您希望在具有指向 A 的指针或引用时调用 class B 的方法(),则必须创建查找 table。此 table 被称为 vtable(来自虚函数 table),它是通过向函数添加 virtual 关键字来定义的。
#include <iostream>
class A {
public:
virtual ~A(){}
virtual int method() = 0;
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() {
std::cout << "Calling method() from B" << std::endl;
return foo; }
};
class C {
private:
A* baz;
public:
C(A* faz) { baz = faz; }
A* get() { return baz; }
};
int main(void) {
A* element = new B(1);
C boo(element);
boo.get()->method();
return 0;
}
它打印 "Calling method() from B"。请记住,该代码仅用于演示目的,从最佳实践的角度来看并不好。
首先,为了多态地使用A
,你需要添加一个virtual
析构函数,否则在试图销毁对象时你会运行进入未定义的行为。那么你想通过 A
调用的方法也必须是 virtual
。如果它不应该在基础 class 本身中有一个实现,让它成为纯虚拟的:
class A {
protected:
int foo;
public:
virtual ~A() {}
virtual int method() = 0;
};
然后在 C
中,您需要使用指向 A
的指针或引用,因为多态性仅适用于这些。
如果您希望 C
拥有 A
,正如您的代码示例所建议的,那么您需要提供一个删除指针的析构函数,并且您需要禁用 [=31] 的复制=](或为它决定一些有用的语义):
class C {
private:
C(const C&); // Don't allow copying
C& operator=(const C&); // Don't allow copying
A* baz;
public:
C(A* faz) : baz(faz) { }
~C() { delete baz; }
A& get() { return *baz; }
};
int main(void) {
C boo(new B(1));
C boz(new D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
理想情况下,您将升级到 C++11 并使用 std::unique_ptr<A>
而不是 A*
作为成员。但即使你不能这样做,也可以考虑使用 boost::scoped_ptr<A>
,它将为你管理删除(你不需要析构函数)并且默认情况下会使 class 不可复制。它还提供更好的异常安全性来将分配封装在这样的智能指针中。
#include <iostream>
class A {
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() { return foo; }
};
class C {
private:
A baz;
public:
C(A faz) { baz = faz; }
A get() { return baz; }
};
int main(void) {
C boo(B(1));
std::cout << boo.get().method() << std::endl;
return 0;
}
我有一个基础 class A
,其中 B
是 class 的派生。 Class C
采用 A
但我已经通过派生的 class (B
) 代替它。没有警告或错误将 B
传递给 C
,但我希望在上述情况下具有 method()
的方法可见性。
我对 virtual
不是很熟悉,但我确实尝试将 virtual int method() = 0;
添加到 A
,这会导致更多错误。
考虑我是否要添加第二个派生的 class:
class D : public A {
public:
D(int bar) { foo = bar; }
int method() { return foo+1; }
};
我希望 C
能够接受 B
或 D
我最好的假设是接受 A
并让它处理它.
如何以这种方式正确使用多态性?
预期输出如下:
int main(void) {
C boo(B(1));
C boz(D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
将是:
1
3
如果您需要使用基础 class 类型 A 调用类型 B 的方法 (),则必须在 运行时 期间进行查找。查找是回答以下问题所必需的:应该调用哪个方法? - 与当前行中的类型相对应的那个?还是继承层次结构中的其他方法?” 如果您希望在具有指向 A 的指针或引用时调用 class B 的方法(),则必须创建查找 table。此 table 被称为 vtable(来自虚函数 table),它是通过向函数添加 virtual 关键字来定义的。
#include <iostream>
class A {
public:
virtual ~A(){}
virtual int method() = 0;
protected:
int foo;
};
class B : public A {
public:
B(int bar) { foo = bar; }
int method() {
std::cout << "Calling method() from B" << std::endl;
return foo; }
};
class C {
private:
A* baz;
public:
C(A* faz) { baz = faz; }
A* get() { return baz; }
};
int main(void) {
A* element = new B(1);
C boo(element);
boo.get()->method();
return 0;
}
它打印 "Calling method() from B"。请记住,该代码仅用于演示目的,从最佳实践的角度来看并不好。
首先,为了多态地使用A
,你需要添加一个virtual
析构函数,否则在试图销毁对象时你会运行进入未定义的行为。那么你想通过 A
调用的方法也必须是 virtual
。如果它不应该在基础 class 本身中有一个实现,让它成为纯虚拟的:
class A {
protected:
int foo;
public:
virtual ~A() {}
virtual int method() = 0;
};
然后在 C
中,您需要使用指向 A
的指针或引用,因为多态性仅适用于这些。
如果您希望 C
拥有 A
,正如您的代码示例所建议的,那么您需要提供一个删除指针的析构函数,并且您需要禁用 [=31] 的复制=](或为它决定一些有用的语义):
class C {
private:
C(const C&); // Don't allow copying
C& operator=(const C&); // Don't allow copying
A* baz;
public:
C(A* faz) : baz(faz) { }
~C() { delete baz; }
A& get() { return *baz; }
};
int main(void) {
C boo(new B(1));
C boz(new D(2));
std::cout << boo.get().method() << std::endl;
std::cout << boz.get().method() << std::endl;
return 0;
}
理想情况下,您将升级到 C++11 并使用 std::unique_ptr<A>
而不是 A*
作为成员。但即使你不能这样做,也可以考虑使用 boost::scoped_ptr<A>
,它将为你管理删除(你不需要析构函数)并且默认情况下会使 class 不可复制。它还提供更好的异常安全性来将分配封装在这样的智能指针中。