传承与朋友:安全机制?
Inheritance and Friends: Safety mechanism?
我遇到了一个有趣的理论,我想知道 c++ 中是否有针对此的安全机制。
class Base
{
private:
virtual void a(){};
friend class C;
}
class Derived: public Base
{
void a() override {};
}
class C{
public doSomething(const Base& b) {b.a();};
}
所有这些都是合法的 - class C 是 base 的友元,因此可以调用 b.a()。然而,当它接收到一个引用时,它可以接收到一个 Derived 对象的引用,因此 C 将访问 class Derived 中的私有区域,而不是 derived.
的朋友。
这仅仅是糟糕的代码设计,还是有防范措施?当覆盖 operator<< 并从内部调用通用打印函数时发生在我身上(操作员是 base 的朋友)。
这里不需要任何保护措施。这就是 C++ 设计的工作方式。
通过覆盖基 class 中的虚函数,派生的 class 重新实现了它。但是 "reimplementing" 的定义包括从基础 class 继承所有的包袱。包括基础 class 中的虚函数在这种情况下是 public
.
派生的 class 将重新实现的函数定义为 private
这一事实不会改变它重写 public 函数的事实。因此,它应该期望它仍然可以通过基础 class.
访问
最多,我想,你可以称之为"quirk"。最重要的是,如果您要覆盖 public
虚函数,则覆盖过程不会改变它是 public 函数的事实。在派生的 class 中创建覆盖函数 "private" 是在马匹离开后关闭谷仓。
而且您必须意识到您正在覆盖 public 虚函数这一事实。在某些情况下,我会说这甚至可以成为一项功能。不难想象这样一种情况,即特定基 class 函数只能由直接引用基 class 的现有代码调用。任何具有指向派生 class 的指针或引用的代码都是更高级别的代码,不应有任何业务调用基 class 的函数。当然,这是一种方法。这当然不是某种严格的安全性,而只是编译器帮助您捕获逻辑或功能错误或某种设计错误的机制。
嗯,不,这不是 C++ 的糟糕设计。你的程序设计不好。
一个类似
的程序
some_C.doSomething(some_derived);
将无法编译。这是因为你的 Base
是 Derived
的私人基地。所以 Derived &
到 Base &
的转换是无效的。
上述情况的例外情况是执行此操作的调用函数是 Derived
的成员或 friend
。在那种情况下,行为由Derived
的(开发者)控制,如果你做了这样的事情,那完全是你的责任。
作为(Base 和 Derived)设计的骨架,这是 Herb Sutter 15 years ago 提倡的典型的好设计 - 除了让 class C 成为朋友是多余的,因为它可以调用 public 函数 运行()。只有当 C 只需要使用 a() 时,它才需要成为友元,以防 运行() 有更多的功能需要避免(我怀疑在这种情况下设计不好)。
我想知道我的阅读有什么问题,因为与前面的答案不同,我没有看到 a() 是 public,也没有看到 Base 是私有基地。
享受
我遇到了一个有趣的理论,我想知道 c++ 中是否有针对此的安全机制。
class Base
{
private:
virtual void a(){};
friend class C;
}
class Derived: public Base
{
void a() override {};
}
class C{
public doSomething(const Base& b) {b.a();};
}
所有这些都是合法的 - class C 是 base 的友元,因此可以调用 b.a()。然而,当它接收到一个引用时,它可以接收到一个 Derived 对象的引用,因此 C 将访问 class Derived 中的私有区域,而不是 derived.
的朋友。这仅仅是糟糕的代码设计,还是有防范措施?当覆盖 operator<< 并从内部调用通用打印函数时发生在我身上(操作员是 base 的朋友)。
这里不需要任何保护措施。这就是 C++ 设计的工作方式。
通过覆盖基 class 中的虚函数,派生的 class 重新实现了它。但是 "reimplementing" 的定义包括从基础 class 继承所有的包袱。包括基础 class 中的虚函数在这种情况下是 public
.
派生的 class 将重新实现的函数定义为 private
这一事实不会改变它重写 public 函数的事实。因此,它应该期望它仍然可以通过基础 class.
最多,我想,你可以称之为"quirk"。最重要的是,如果您要覆盖 public
虚函数,则覆盖过程不会改变它是 public 函数的事实。在派生的 class 中创建覆盖函数 "private" 是在马匹离开后关闭谷仓。
而且您必须意识到您正在覆盖 public 虚函数这一事实。在某些情况下,我会说这甚至可以成为一项功能。不难想象这样一种情况,即特定基 class 函数只能由直接引用基 class 的现有代码调用。任何具有指向派生 class 的指针或引用的代码都是更高级别的代码,不应有任何业务调用基 class 的函数。当然,这是一种方法。这当然不是某种严格的安全性,而只是编译器帮助您捕获逻辑或功能错误或某种设计错误的机制。
嗯,不,这不是 C++ 的糟糕设计。你的程序设计不好。
一个类似
的程序 some_C.doSomething(some_derived);
将无法编译。这是因为你的 Base
是 Derived
的私人基地。所以 Derived &
到 Base &
的转换是无效的。
上述情况的例外情况是执行此操作的调用函数是 Derived
的成员或 friend
。在那种情况下,行为由Derived
的(开发者)控制,如果你做了这样的事情,那完全是你的责任。
作为(Base 和 Derived)设计的骨架,这是 Herb Sutter 15 years ago 提倡的典型的好设计 - 除了让 class C 成为朋友是多余的,因为它可以调用 public 函数 运行()。只有当 C 只需要使用 a() 时,它才需要成为友元,以防 运行() 有更多的功能需要避免(我怀疑在这种情况下设计不好)。 我想知道我的阅读有什么问题,因为与前面的答案不同,我没有看到 a() 是 public,也没有看到 Base 是私有基地。 享受