C++中的类型和名称有什么区别?
What's the difference between type and name in C++?
我正在阅读此堆栈;
class Foo {
struct Bar {
int i;
Bar(int a = 5) :i(a) {};
};
public:
Bar Baz() { return Bar(); }
};
int main() {
Foo f;
// Foo::Bar b = f.Baz(); // error
auto b = f.Baz(); // ok
std::cout <<"b.i="<< b.i<<endl;
return 0;
}
代码输出b.i=5
。在这个问题中,它得出的结论是,私人名称无法访问,但类型是。那么,通常类型和名称之间有什么区别?
说我有两个具体的情况。
-
以下两个声明有什么区别?为什么我可以从
auto b = f.Baz();
获得输出b.i=5
?Foo::Bar b = f.Baz(); auto b = f.Baz();
-
如果我在
Foo
的公共部分中添加typedef Bar B;
,以下内容有什么区别?Foo::Bar b = f.Baz(); Foo::B b = f.Baz();
如果方案1和2之间存在区别?
类型和名称
有什么区别
类型没有一个或几个名称。Typedef和别名只是为一种类型创建新名称的手段。
public
和private
关键字与非基础类型或成员的名称有关。
为了明确声明特定类型的对象,您需要该类型的名称。auto
不需要。例如,如果您使用未命名的类作为返回类型,则该类没有名称,但是在其上仍然可以使用自动。
一种类型总是具有一个"真名"。即使通过Typedef或别名使用它,编译器也会以此名称使用它(或实际上是此名称的原始版本)。所以:
class A {};
typedef A B;
std::cout << typeid(B).name();
打印" A类"。一个未命名的对象不能给出"真名"。但是,使用typedef
和decltype
。可以创建一个新名称。如果此名称用于创建对象。typeid().name
将打印新分配的名称。如果对象未命名以" true Name"名称开始。
方案:
区别在于,在第一个您使用私人声明的名称中。这是非法的。这与类型扣除的不同方式工作有关。正如斯科特·迈耶斯(Scott Meyers)在这里解释的那样。由于公共功能呼叫提供了此类型,因此返回类型是公共的。但是,
Bar
本身不是公开的。这是一个很小的差异,但这就是原因。
这只是设计中已经做出的决定。这是有道理的,有时您只希望在返回时使用结构。也是如此。没有区别,但是
Foo::Bar
根本无法访问。
编辑
您可以举个例子,该类型没有名称?以上评论中未命名的联盟是一个例子吗?
如下所述,我使用lambda函数如下:
auto f = [] () -> struct {int x, y ; } { return { 99, 101 } ; } ;
不使用自动或声明类型,就无法创建变量f
。由于类型没有名称。没有名称的类型的另一个示例。
struct foo
{
struct{
int x;
int y;
} memberVar;
};
将允许您执行以下操作:
foo bar;
auto baz = bar.memberVar;
std::cout << baz.x;
当然会导致许多初始化的东西,但是您会明白:)。memberVar
的类型未命名。使得无法明确定义baz
。
并且被认为是INT类型的名称?
int
有点特别,是一种基本类型。" int"确实是类型int的名称。但这绝不是唯一的名称int32_t
,例如,大多数编译器上完全相同类型的另一个名称(在其他系统上,int16_t
等于int
)。
std::cout << typeid(int32_t).name();
打印" int"。
注意:
我避免使用别名作为对象的其他名称的指标,因为这可能会引起与别名关键字的混淆。
我从经验中收集的大部分。所以我可能错过了一些。
由于缺少一个更好的单词,我使用了" true Name"的表达。如果有人知道官员或一个更好的词,我很乐意听到它:)。
[某些标准者前进]
让我们同意auto
扣除的工作方式与模板参数扣除相同的方式:
[dcl.spec.auto]/p7
如果占位符是汽车 类型分类器,推论类型是使用模板参数扣除规则
确定的。
模板在汇编过程中受到两台查找的约束。访问控制应用于第一阶段的名称查找
[basic.lookup]/p1
超载分辨率(13.3)发生在名称查找成功之后。访问规则(第11条)仅一旦名称查找和功能过载分辨率(如果适用)已成功。只有在名称查找后,功能过载分辨率(如果适用)和访问检查成功的属性是该名称声明在表达式处理中进一步使用的属性
auto
和 decltype(auto)
通常是推导类型的占位符,的确, [temp.arg]/p3 说
模板题的名称应在用作模板argument
的点上访问
但名称在这里不涉及,只有类型。访问控制适用于名称,类型可以映射到0、1或多个名称,这就是您在上面代码中使用auto
时要处理的:它在语义上等同于模板扣除的语义,这是通过设计。
[class.access]/p4
访问控制均统一地应用于所有名称,无论名称是从声明中提到的,还是 表达。[...]可访问性 不考虑TypedEF提到的实体。例如
class A {
class B { };
public:
typedef B BB;
};
void f() {
A::BB x; // OK, typedef name A::BB is public
A::B y; // access error, A::B is private
}
说服您自己以下内容查看相同的代码,其中涉及的模板参数扣除(概念上等同于auto
版本)
template<class T>
T deduce(T t) {
return t;
}
class Foo {
struct Bar{
int i;
Bar(int a = 5):i(a){};
};
public:
Bar *getB() { return new Bar(5); } // Leaks, doesn't matter for clarity's sake
};
int main() {
Foo f;
std::cout <<"b.i="<< deduce(f.getB())->i <<std::endl; // Prints 'b.i=5'
return 0;
}
实例示例
在上述代码中不涉及,因此不适用访问控件。确实涉及类型。
auto
的语义就像隐式模板扣除(规范措辞也直接指)。
其他人以前有这种疑问。
现在答案:
Case 1
如果您认为呼叫者无法访问Foo::Bar
。
Case 2
也将名称公开给呼叫者,因此,如果您使用typedef名称,您的代码将愉快地编译。
您的问题链接解释了很多,但作为对那里写的内容的补充...
-
主要区别在于,在第二行
auto b=...
中,您让编译器推断出表达式的类型。您无法指定类型,因为该类型的名称被隐藏。类型是可用的(至少来自编译器) -
您可以公开公开该类型的名称,因此可以使用。
这是一个很好的答案https://stackoverflow.com/a/13532882/3037915
尝试回答标题中的问题,您可以将类型键入形状和类型的名称,作为您用来指代特定形状的名称。即使隐藏了"形状"的名称,形状仍然存在并且可以使用。
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- Qt:remove() 和 rmdir() 有什么区别
- 这 4 个 lambda 表达式之间有什么区别?
- 将向量作为类>(值)<向量启动和向量<类>[值]有什么区别
- typedef 枚举和枚举类有什么区别?
- &C::c 和 &(C::c) 有什么区别?
- ascii 和 unicode 在处理级别有什么区别吗?
- C 中的常量限定符和 C++ 中的常量限定符有什么区别?
- "ABC" 和 "ABC" ) 在C++中有什么区别?
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- 两种访问I2C总线的方法有什么区别?
- 两种模板示例有什么区别?
- 这两种C++语法之间有什么区别?
- lua 5.0.2 模块和 5.3.5 有什么区别?
- C++中"typedef"、"using"、"namespace"和"using namespace"有什么区别?
- std::enable_if 和 std::enable_if_t 有什么区别?