我已经看到,为了检查类型T
是否是我可以使用的类:
bool isClass = std::is_class<T>::value;
它对类和结构都返回true。我知道在C ++中它们几乎是一样的,但我想知道为什么在类型特征中它们之间没有区别。检查这种差异总是没用,还是有一些我不理解的理由?
它对类和结构都返回true。我知道在C ++中它们几乎是一样的,但我想知道为什么在类型特征中它们之间没有区别。
不幸的是,这是C ++中常见的误解。有时它来自于基本的误解,但有时它来自于英语的含糊不清。它可能来自不准确的编译器诊断,写得不好的书,不正确的SO答案......
你可能读过这样的东西:
“除了成员和基础的默认可见性之外,结构和类之间的C ++没有区别。”
这段经文可以被误解,因为在使用诸如“无差异”之类的短语时,很难区分身份和平等的概念。
事实上,自1985年以来,C ++还没有结构。它只有类。
The kind of types that you declare with the keyword class
and the keyword struct
are classes。期。关键字struct
和使用该关键字定义类时默认的可见性规则只是为了与C ...向后兼容而保留,但这是一种语法。它不会使得到的类型实际上是另一种类型。
类型特征没有区别,因为字面意思不是一个要做的。
对于像空的定义,不可能区分语义的差异
class C {
public:
};
从
struct S {
};
或类似的
class C {
};
和
struct S {
private:
};
除了struct
与class
关键字之外,没有可检测到的行为差异。另见this Q&A。
注意:正如@KyleStrand所述,派生也需要显式访问说明符,所以S : private Base {};
和C : Base {};
是等价的,与S : Base {};
和C : public Base {};
相同,其中S
是一个结构,C
是一个类,Base
可以是。
他们是一回事。唯一的区别(默认成员可见性)仅在编译时存在。 struct
和class
之间没有任何区别。
ETA:你可能想要的是std::is_pod
,它会告诉你你的班级是否是“普通旧数据类型”。关于这个问题的大部分讨论和评论似乎表明,这就是那些认为应该有区别的人真正想要的。
其他人正确地指出,在C ++中,关键字struct
和class
具有相同的含义,除了成员可见性的差异。
您是否调用聚合类型,因此定义“结构”或“类”或“weiruewzewiruz”取决于您。为了沟通,通常建议遵循既定的惯例,因此我建议反对“weiruewzewiruz”。
还建议使用语义差异作为单词选择的指导。对于简单的聚合数据,struct
的使用更为常见,它没有很多内部逻辑和不变量;典型的用途是struct point { float x; float y; };
。这些类型在文献中通常称为“结构”或“结构”。如果有人在C ++中使用fprintf
将第一个参数称为“指向FILE结构的指针”,那就不足为奇了。 FILE是Scott Meyers在“更有效的C ++”中的含义的一个例子,第34项:
可以安全地假设两种语言编译的结构定义[C和C ++ -p.a.s]由两个编译器以相同的方式排列。
关于自然语言,单词选择“结构”并非巧合:迈耶斯正在谈论一种普通的旧数据集合,它在两种语言中具有相同的语义,直到位级别。
关于编程语言,如果所讨论的数据聚合的C ++定义使用关键字struct
或class
(使用公共访问说明符),则无关紧要。 struct
可能是更自然的选择,因为聚合的C ++语义是C结构的语义。此外,使用struct
可以使C和C ++源更容易共享一个类型定义。
C ++标准在自然语言和编程语言中都使用“struct”和“structure”,不仅在互操作性的情况下:1.7 / 5:“结构声明为”,或3.2 / 4 struct X; // declare X as a struct type
。最有趣的是9/8,为互操作标准奠定了基础:
标准布局结构是使用类键结构或类键类定义的标准布局类。 [...]
任何阅读此内容的人都可以声称C ++中没有任何结构是超出我的。这显然不是编辑错误,因为术语“struct”和“class”是相互明确设置的。
然而,比单词选择和品味问题更有趣的是明显的,可测试的差异。在什么情况下C ++聚合与C struct
相当并兼容?也许这个问题是你的问题的根源?报价中提到的标准布局是标准。它在9/7中详细说明,并且基本上规定了这一点
然后标准说
9 [注意:标准布局类对于与使用其他编程语言编写的代码进行通信非常有用。它们的布局在9.2中指定.-尾注]
当然,在C中编译的结构定义符合这些标准,因此Scott Meyers的断言。来自stdio.h的FILE
是一个突出的,不是非常重要的例子。请注意,标准不保证,因为对象布局是依赖于实现的,并且可能仅使用编译器选项进行更改。
是否具有标准布局的类可以使用类型特征std::is_standard_layout<T>
进行测试。以下程序受an example on cppreference的启发,检查标准中列出的主要案例。
#include <cstdio>
#include <typeinfo>
#include <type_traits>
using namespace std;
struct funcOnlyT // fine
{
int f();
};
class podT { // "class" is ok
int m1;
int m2;
};
struct badAccessCtrlT { // bad: public/private
int m1;
private:
int m2;
};
struct polymorphicT { // bad: polymorphic
int m1;
int m2;
virtual void foo();
};
struct inheritOkT: podT // ok: inheritance, data only on one level
{
int f();
};
struct inheritPlusDataT: podT // bad: inheritance, data on 2 levels
{
int m3;
};
template<typename T1, typename T2>
struct templT // ok with std layout types T1, T2
{
T1 m1;
T2 m2;
};
// print type "name" and whether it's std layout
template<typename T>
void printIsStdLayout()
{
printf("%-20s: %s\n",
typeid(T).name(),
std::is_standard_layout<T>::value
? "is std layout"
: "is NOT std layout");
}
int main()
{
printIsStdLayout<funcOnlyT>();
printIsStdLayout<podT>();
printIsStdLayout<badAccessCtrlT>();
printIsStdLayout<polymorphicT>();
printIsStdLayout<inheritOkT>();
printIsStdLayout<inheritPlusDataT>();
printIsStdLayout<templT<int, float> >();
printIsStdLayout<FILE>();
}
示例会话:
$ g++ -std=c++11 -Wall -o isstdlayout isstdlayout.cpp && ./isstdlayout
9funcOnlyT : is std layout
4podT : is std layout
14badAccessCtrlT : is NOT std layout
12polymorphicT : is NOT std layout
10inheritOkT : is std layout
16inheritPlusDataT : is NOT std layout
6templTIifE : is std layout
9__sFILE64 : is std layout
C++11 §9/10 ([class]/10):“标准布局结构是使用类密钥
struct
或类密钥class
定义的标准布局类。标准布局联合是使用类密钥union
定义的标准布局类。
“POD结构是一个非联合类,它既是一个普通类,也是一个标准布局类,并且没有非POD结构,非POD联合(或这类类型的数组)类型的非静态数据成员。 [...]
由于POD结构是标准布局类,因此它是标准布局结构的子集。据我所知,这是C ++标准中struct的最一般含义。所以你想要的是一个类型特征或一组类型特征,它们可以让你识别标准布局结构。
而且,查看类型特征列表的是is_class
和is_standard_layout
。当一种类型令人满意时,它就是一个“结构”。或者更确切地说,它是标准布局结构,由C ++11§9/ 8定义。
关于
“我想知道为什么类型特征中的[class和struct]之间没有区别
好吧,有。那就是is_standard_layout
的特质。
关于
“检查这种差异总是没用,还是有一些我不理解的理由?
不,检查这种差异并非毫无用处。该标准定义了标准布局,因为它非常实用。正如标准本身所说,
C++11 §9/9 ([class]/9):“[注意:标准布局类对于与用其他编程语言编写的代码进行通信非常有用。它们的布局在9.2中指定.-尾注]
笔记:
¹is_class
特性适用于class
或struct
,但不适用于union
,尽管该标准定义“一个联盟是一个阶级”。即特征比一般术语更具体。