我正在阅读关于C++ POD,Trivial和Standard Layout类的精彩文章 我对标准布局没有清楚了解的一个属性如下: -
A standard layout has no base classes of the same type as the first
non-static data member
Run Code Online (Sandbox Code Playgroud)
因此,以下将不是标准布局,因为它具有与基类相同的第一个成员
struct NonStandardLayout3 : StandardLayout1 {
StandardLayout1 x; // first member cannot be of the same type as base
};
Run Code Online (Sandbox Code Playgroud)
但是在性能方面和属性方面,上述结构有何不同
struct StandardLayout5 : StandardLayout1 {
int x;
StandardLayout1 y; // can have members of base type if they're not the first
};
Run Code Online (Sandbox Code Playgroud)
这是对此之上的修正.
据我所知,标准布局允许三件事:
现在,包含在库中的是is_standard_layout谓词元函数,但我在通用代码中看不到它的用处,因为我上面列出的那些C特性似乎极少需要检查通用代码.我唯一能想到的是在里面使用它static_assert,但这只是为了使代码更健壮而且不是必需的.
怎么is_standard_layout有用?有没有没有它的东西是不可能的,因此需要它在标准库中?
我将一个简单的C++继承层次结构包装成"面向对象的"C.我试图弄清楚是否有任何问题将C++对象的指针视为指向不透明C结构的指针.特别是,在什么情况下派生到基础的转换会导致问题?
类本身相对复杂,但层次结构很浅并且仅使用单继承:
// A base class with lots of important shared functionality
class Base {
public:
virtual void someOperation();
// More operations...
private:
// Data...
};
// One of several derived classes
class FirstDerived: public Base {
public:
virtual void someOperation();
// More operations...
private:
// More data...
};
// More derived classes of Base..
Run Code Online (Sandbox Code Playgroud)
我计划通过以下相当标准的面向对象的C向C客户端展示它:
// An opaque pointers to the types
typedef struct base_t base_t;
typedef struct first_derived_t first_derived_t;
void base_some_operation(base_t* object) {
Base* base = (Base*) object; …Run Code Online (Sandbox Code Playgroud) 更新:我非常感谢“不要那样,要这样”的建议。它们很有用,尤其是在有启发性的情况下提供时。仍然……不管优缺点,我一直好奇地找到一个坚定不移的“是的,可以在C ++ 11中合法地完成”与“没有,不可能那样做”。
我想“别名”一个对象指针作为另一种类型,其唯一目的是添加一些辅助方法。别名不能将数据成员添加到基础类中(实际上,我可以阻止它发生的次数越多越好!)所有别名都同样适用于此类型的任何对象……如果类型系统可以提示哪个别名,则只会有帮助别名可能是最合适的。
应该没有有关在基础对象中编码的任何特定别名的信息。因此,我觉得您应该能够“欺骗”类型系统,并使其成为注解...在编译时进行检查,但最终与运行时转换无关。遵循以下原则:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
Run Code Online (Sandbox Code Playgroud)
在幕后,factory方法实际上是在创建一个NodeBase类,然后使用类似的方法reinterpret_cast将其返回为a Node<AccessorFoo>*。
避免这种情况的简单方法是使这些轻量级类包装节点并按值传递。因此,您不需要强制转换,只需将带有节点句柄的Accessor类包装在其构造函数中即可:
AccessorFoo foo (NodeBase::createViaFactory());
AccessorBar bar (foo.getNode());
Run Code Online (Sandbox Code Playgroud)
但是,如果我不必为此付出任何代价,那我就不想。例如,这将涉及为每种包装的指针(AccessorFooShared,AccessorFooUnique,AccessorFooWeak等)创建一种特殊的访问器类型,最好将这些类型化的指针别名为一个基于单个指针的对象标识,并提供一个很好的正交性。
回到最初的问题:
Node<AccessorFoo>* fooPtr = Node<AccessorFoo>::createViaFactory();
Node<AccessorBar>* barPtr = reinterpret_cast< Node<AccessorBar>* >(fooPtr);
Run Code Online (Sandbox Code Playgroud)
似乎有某种方法可以做到这一点可能很丑陋,但不能“违反规则”。根据ISO14882:2011(e)5.2.10-7:
可以将对象指针显式转换为其他类型的对象指针。70将“指向T1的指针”的prvalue v转换为“指向Cv T2的指针”时,结果为static_cast(static_cast(v))如果T1和T2均为标准布局类型(3.9),并且T2的对齐要求不严格于T1的对齐要求,或者任一类型均无效。将类型为“指向T1的指针”的prvalue转换为“指向T2的指针”的类型(其中T1和T2是对象类型,并且T2的对齐要求不严格于T1的对齐要求)并返回其原始类型指针值。未指定任何其他此类指针转换的结果。
深入研究“标准布局类”的定义,我们发现:
听起来像使用类似的东西会有点费劲,而访问器或节点中没有虚拟方法。但是C ++ 11显然必须std::is_standard_layout保持检查状态。
这样可以安全吗?似乎可以在gcc-4.7中使用,但是我想确定自己没有调用未定义的行为。
我有以下课程:
class SSVec
{
public:
float values[8];
}
Run Code Online (Sandbox Code Playgroud)
我有一个对象SSVec obj,我将float*指针传递obj.values给另一个函数.在代码的其他地方,我得到这个float*指针,然后用魔杖将它强制转换为SSVec*指针.
这是否可能以C++标准定义的行为方式?大部分时间这都适用于静态演员,但我的猜测是它实际上是未定义的行为.
这样做的原因是float*指针传入和传出DLL,它对SSVec一无所知.我保证传递的指针始终指向SSVec :: value [8]对象成员.
该类可能更复杂,但它不是从任何东西派生,没有虚函数,只包含POD类型.values是第一个成员
问题可以重新制定:班级地址和第一个成员地址是否保证是相同的static_cast?
这是一个很大的问题,因此我要求参考而不是小册子大小的答案。我正在进行Stroustrup的C ++之旅,看来对象的布局方式是内存是许多C ++功能设计的基础,例如POD,聚合,带有虚拟成员的类。
不幸的是,Tour本身并没有详细介绍此主题,而对一些标准参考文献(例如C ++ Primer 5ed和TCPPPL 4ed)的ToC进行浏览并不能显示它们是否涉及该主题。
我必须解决一个问题,包括在c ++中对数字列表进行排序.条件是:
如果A = {4,-8,7,-6,0,-7,5},则最终B = {0,4,5,7,-6,-7,-8}
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int i,j,n,A[100],B[100],A_nenegative[100],A_negative[100],aux,m=0,k=0;
cout<<"max elements"; cin>>n;
cout<<"elements are"<<endl;
for(i=0;i<n;i++)
{
cin>>A[i];
}
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(A[i]>A[j])
{
aux=A[i];
A[i]=A[j];
A[j]=aux;
}
for(i = 0; i< n; i++)
if(A[i]>=0) {
A_nenegative[i]=A[i];
B[i]=A_nenegative[i];
k++;
}
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(A[i]<A[j])
{
aux=A[i];
A[i]=A[j];
A[j]=aux;
}
for(i=0;i<n;i++)
if(A[i]<0)
{
A_negative[i]=A[i];
m++;
}
}
Run Code Online (Sandbox Code Playgroud)
这是我停下来的地方.我在A_negative中对A_nenegative和负数中的正数进行排序.所以问题是如何将B属性首先归结为A_nenegative然后归属于A_negative.我尝试将正数排序后立即归属于B,类似于:
for(i = 0; i< n; i++)
if(A[i]>=0) {
A_nenegative[i]=A[i];
B[i]=A_nenegative[i];
k++;
} …Run Code Online (Sandbox Code Playgroud)