为什么虚函数违抗访问说明符? C++
Why virtual functions defy access specifiers ? C++
让我们假设你有一个 class base 和 class A 继承自 base 。 base 有一个名为 getValue() 的纯虚函数的声明,它是 public ,并且 A 包含设置为 private 的函数的定义(实现)。
当尝试使用从基引用或指针 (base& /base*) 到 A 对象的函数 getValue() 时,即使它被声明为 private
,它也会访问它
因为在 C++ 中,虚拟性和访问是正交的。当编译器看到 base*
或 base&
并且需要对其调用 getValue
时,那么在 base
.
中可以访问该函数就足够了
A
将其(覆盖)getValue
声明为 private
的事实无关紧要。毕竟,它怎么可能相关呢?当 base.getValue()
或 base->getValue()
被调用时,您 不知道 您可能正在处理一个 A
。这首先就是面向对象编程的全部意义!
不过,这并不意味着在 class 层次结构中改变访问说明符是好的风格,因为它可能会造成混淆。事实上,您应该将 getValue
分成两个不同的函数,一个是虚拟函数,另一个是非虚拟函数。
长话短说:C++ 在这里的行为与其他流行的编程语言非常不同,因为它实际上允许并鼓励 private virtual 函数。 virtual成员函数默认是private的,public成员函数默认是non-virtual的,必要时调用private的virtual。 (当然,唯一的例外是析构函数。)Herb Sutter 曾将其称为 Non-Virtual Interface Idiom.
示例:
#include <iostream>
class Base
{
public:
virtual ~Base() {}
int getValue() const
{
int const value = doGetValue();
if (value < 0)
{
// error
}
return value;
}
private:
virtual int doGetValue() const = 0;
};
class A : public Base
{
private:
int doGetValue() const override
{
return 123;
}
};
int main()
{
Base* ptr = new A; // use std::unique_ptr in real code
std::cout << ptr->getValue() << "\n";
delete ptr;
}
让我们假设你有一个 class base 和 class A 继承自 base 。 base 有一个名为 getValue() 的纯虚函数的声明,它是 public ,并且 A 包含设置为 private 的函数的定义(实现)。 当尝试使用从基引用或指针 (base& /base*) 到 A 对象的函数 getValue() 时,即使它被声明为 private
,它也会访问它因为在 C++ 中,虚拟性和访问是正交的。当编译器看到 base*
或 base&
并且需要对其调用 getValue
时,那么在 base
.
A
将其(覆盖)getValue
声明为 private
的事实无关紧要。毕竟,它怎么可能相关呢?当 base.getValue()
或 base->getValue()
被调用时,您 不知道 您可能正在处理一个 A
。这首先就是面向对象编程的全部意义!
不过,这并不意味着在 class 层次结构中改变访问说明符是好的风格,因为它可能会造成混淆。事实上,您应该将 getValue
分成两个不同的函数,一个是虚拟函数,另一个是非虚拟函数。
长话短说:C++ 在这里的行为与其他流行的编程语言非常不同,因为它实际上允许并鼓励 private virtual 函数。 virtual成员函数默认是private的,public成员函数默认是non-virtual的,必要时调用private的virtual。 (当然,唯一的例外是析构函数。)Herb Sutter 曾将其称为 Non-Virtual Interface Idiom.
示例:
#include <iostream>
class Base
{
public:
virtual ~Base() {}
int getValue() const
{
int const value = doGetValue();
if (value < 0)
{
// error
}
return value;
}
private:
virtual int doGetValue() const = 0;
};
class A : public Base
{
private:
int doGetValue() const override
{
return 123;
}
};
int main()
{
Base* ptr = new A; // use std::unique_ptr in real code
std::cout << ptr->getValue() << "\n";
delete ptr;
}