c++ - 沿类层次结构的函数指针强制

标签 c++ undefined-behavior type-coercion

考虑下面的代码:

#include <type_traits>
#include <iostream>

struct B {
    virtual const char* whoami() const { return "I am a B!\n"; };
};

struct D : B {
    const char* whoami() const override { return "I am a D!\n"; };
};

void foo_impl( B*(*pf)() )
{
    B* b = pf();
    std::cout << b->whoami();
}

template <class C>
auto foo( C*(*pf)() ) -> std::enable_if_t<std::is_base_of<B, C>::value> {
    foo_impl(reinterpret_cast<B*(*)()>(pf));
}

D *bar() {
    static D d_; // kludge to work around dangling pointer problem.
                 // Unrelated to the actual question
    return &d_;
}

int main() {
    foo(bar); // prints "I am a D!" on gcc 5.1
    return 0;
}

函数指针当然不能根据标准进行强制转换,也许也没有必要(我们总是可以返回一个 B* ),但请幽默一下。据我所知,没有可能违反 LSP,所以如果可能的话,一个返回 D* 的函数可以用来代替返回 B* 的函数以完全不透明的方式。

foo模板执行我希望编译器执行的静态类型检查,然后将类型信息抛到脑后。此时,我知道除非我转换回原始指针类型,否则行为是未定义的 (C++11 §5.2.10/6)。

因此我的问题是:

是否有与标准无关的实际原因导致上述代码失败?或者是否有其他标准引用,可以缓解上述代码中 UB 的不愉快?

最佳答案

您帖子的以下陈述不正确:

a function returning D* could be used in place of a function returning B* in a completely opaque manner

这不是真的,因为将 D* 转换为 B* 不仅仅是一个强制转换:可能需要地址的移位。它不在您的示例中,因为您不使用多重继承。

考虑这个例子:

#include <type_traits>
#include <iostream>

struct A {
  int i = 0;
  int whoami() const { return i; };
};

struct B {
  int j = 1;
  int whoami() const {
    std::cout << "Woohoo B is called.\n";
    return j;
  };
};

struct D : A, B {
};

void foo_impl(B *(*pf)()) {
  B *b = pf();
  char const * identity = (0 == b->whoami() ? "A" : "B");
  std::cout << "I am " << identity << std::endl;
}

template <class C>
auto foo( C*(*pf)() ) -> std::enable_if_t<std::is_base_of<B, C>::value> {
      foo_impl(reinterpret_cast<B*(*)()>(pf));
}

D *bar() {
  static D d_;
  return &d_;
}

int main() {
  foo(bar);
  return 0;
}

这会打印出 I am A,即使您认为您使用的是 B。调用的函数实际上是 B::whomai,但下面的数据成员是来自 A 的,因为地址没有像使用适当的地址那样移动指针的 static_cast

关于c++ - 沿类层次结构的函数指针强制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41221701/

相关文章:

c++ - 我需要在此代码中调用 SafeArrayUnLock 吗?

C++编程,从字符串中读取行

c - 为什么我不能为该指针数组元素分配 NULL 值?

c - 错误 : free(): invalid next size (fast)

clojure - 为什么 (int 10) 会产生一个 Long 实例?

c++ - char 数组作为 placement new 的存储

c++ - 为什么 c++ 中 char 和 bool 的大小相同?

c - 以读取模式打开的流的 fputc() 行为

javascript - JavaScript 类型强制如何以及为何起作用?

perl - 从 ArrayRef[HashRef] 强制 ArrayRef[MyClass]