请考虑以下代码:
#include <iostream>
using namespace std;
class Base
{
public:
int foo;
};
class Derived : public Base
{
public:
float bar;
};
int main()
{
Base** baseArr = new Base*[30];
for (int i=0; i<30; i++)
{
Derived* derived = new Derived();
derived->foo = i;
derived->bar = i * 2.5;
baseArr[i] = derived;
}
//Notice this!
Derived** derivedArr = (Derived**)(baseArr);
for (int i=0; i<30; i++)
cout << "My Base " << i << ": " << derivedArr[i]->foo << ", " << derivedArr[i]->bar << endl;
return 0;
}
将此数组用于数组转换是否安全?整个程序的指针大小相同,所以听起来我不会得到任何填充错误。但是,我知道正确的方法是遍历每个元素并单独转换它。
但是,我试图利用这种类型的强制转换通过使用非泛型私有函数返回数组将我的模板公共函数实现移动到.cpp文件,所以我可以确定我的Base
数组只包含具体的Derived
指针。
private:
Base** Find(function<bool(Base*)> Predicate, int& N); //Implemented in .CPP
public:
template <class T> T** FindByType(int &N) //T is derived from Base
{
//Safe?
return (T**)(Find(
[](Base* b)->bool { return typeid(T) == typeid(b); },
N));
};
当然,这只是一个简化的例子。在这种情况下,我有很多理由使用RTTI。 N用于控制数组大小。
我想知道这种不安全的强制转换是否会因多重继承而失败,例如Derived
类也会继承OtherBase
而我想投靠OtherBase**
,我d也想知道我是否有机会通过这个演员表达到未定义的行为,或者如果我决定使用这个结构,我可能会遇到任何潜在的问题。
答案 0 :(得分:2)
不,这不安全。
指向Derived
的指针与指向Base
的指针不同。指向Derived
的指针可以转换为指向Base
的指针,但最终结果是不同的指针。
因为指向Derived
的指针与指向Base
的指针不同,指向Derived
的指针也不是指向指针的指针。指向Base
的指针。
答案 1 :(得分:1)
不,这是不安全的。
如果某个程序试图通过以下某种类型之外的 glvalue 访问对象的存储值,则行为未定义:
- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- 与对象的动态类型相似的类型(如4.4中所定义),
- 与对象的动态类型对应的有符号或无符号类型的类型
- 与对象的动态类型的cv限定版本对应的有符号或无符号类型的类型,
- 聚合或联合类型,其元素或非静态数据成员中包含上述类型之一(包括递归地,元素或非静态数据成员子集合或包含的联合>,
- 一种类型,它是对象动态类型的(可能是cv限定的)基类类型,
char
或unsigned char
类型。
从Ben
无耻地被盗在将Base**
转换为Derived**
的情况下,这些情况都不属实。