0

在编写本机 c++ 代码时,我看到相同的程序在 xcode(iOS) 中运行良好,但在 eclipse(android) 中崩溃。我可以找到问题代码,这是由于内存访问错误。我想知道为什么 xcode(iOS) 没有遇到同样的错误访问因此崩溃。

实际上我创建了一个类说“class_A”,它继承了其他类说class_B。稍后在代码中,我创建了相同的类实例指针并分配了函数 foo() 的返回对象(属于 class_B),该对象返回超类类型的对象,即 class_B。

代码片段...

class class_A : public class_B
{
public:

};

class_A *tempPart = (class_A *)class_A::foo("abc.png"); 

if(tempPart)
                {


                    -------------------
                   --------------------

 }

现在,在访问 _tempPart 时,程序在 android (eclipse) 上崩溃,但是 xcode(iOS) 总是可以正常工作。我可以弄清楚,因为 fn foo() 返回了 class_B 类型的对象,因此我将一个超类(较小的对象)class_B 的对象分配给了继承的类(一个较大的对象)Class_A 的对象,因此它导致了错误的内存访问。

但我不明白为什么在 xcode(iOS) 上没有看到同样的问题。我是 xcode 和 c++ 的新手,所以请帮助我理解这一点。

4

3 回答 3

2

未定义的行为是未定义的。

访问无效内存之类的操作会导致 C++ 中出现未定义的行为。结果可能经常是崩溃,但 C++ 不保证这样的事情。相反,程序可能只是表现得很奇怪,甚至完全按照您的预期行事,而没有任何错误迹象。不同的实现可能会做不同的事情。

这里有一些信息可能有助于解释为什么 C++ 具有未定义的行为(与 Java 等语言相反,它们非常努力地排除未定义的行为)。

每个 C 程序员都应该知道的关于未定义行为的知识


从您的描述中还不能完全清楚到底出了什么问题。您说将较大的对象分配给较小的对象会导致错误的内存访问,但这不是 C++ 中的分配方式,并且示例代码无论如何都使用指针。以下代码完全合法且定义明确,例如:

struct B {};
struct D : B {
  int i;
  void foo() { i = 100; }
};

B b = D(); // works fine, does not overwrite anything outside b. Slicing occurs.

B *bar() {
  return new D;
}

D *d = (D*)bar(); // works fine because the dynamic type matches.

出现问题的地方是:

B *baz() { return new B; }

D *d = (D*)baz(); // not okay, undefined behavior. Anything can happen now, later, or even before this point.
d->foo(); // might crash, might not.

因此,假设这是您的程序正在执行的操作,Java 中的相同错误被明确定义为导致异常。在 Objective-C 中,消息传递机制将尝试在运行时为选择器找到一个实现,如果它没有找到任何东西,则会发生“无法识别的选择器”异常。

于 2012-12-17T03:44:14.123 回答
0

正如@Bames53 所回答的,这是未定义的行为。一个快速的解决方法是制作class_B::foo一个模板函数并将其重写如下

template <class ReturnClassType>
ReturnClassType *foo(std::string str){

然后,您将其称为

class_A::foo<class_A>("abc.png"); 

如果您使用公共/受保护的函数来初始化返回的对象,这应该可以工作。

于 2012-12-17T03:49:16.833 回答
0

您不能安全地将 B 向上转换为 A。B 没有 _useShader 成员。反之亦然:B* = A*,但不能 A* = B*。您可能想为 A 对象创建一个单独的工厂方法。

于 2012-12-17T03:51:35.720 回答