C++中的类型和名称有什么区别?

What's the difference between type and name in C++?

本文关键字:什么 区别 类型 C++      更新时间:2023-10-16

我正在阅读此堆栈;

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。在这个问题中,它得出的结论是,私人名称无法访问,但类型是。那么,通常类型和名称之间有什么区别?

说我有两个具体的情况。

  1. 以下两个声明有什么区别?为什么我可以从auto b = f.Baz();获得输出b.i=5

    Foo::Bar b = f.Baz();
    auto b = f.Baz();
    
  2. 如果我在Foo的公共部分中添加typedef Bar B;,以下内容有什么区别?

     Foo::Bar b = f.Baz();
     Foo::B   b = f.Baz(); 
    

如果方案1和2之间存在区别?

类型和名称

有什么区别

类型没有一个或几个名称。Typedef和别名只是为一种类型创建新名称的手段。

publicprivate关键字与非基础类型或成员的名称有关。

为了明确声明特定类型的对象,您需要该类型的名称。auto不需要。例如,如果您使用未命名的类作为返回类型,则该类没有名称,但是在其上仍然可以使用自动。

一种类型总是具有一个"真名"。即使通过Typedef或别名使用它,编译器也会以此名称使用它(或实际上是此名称的原始版本)。所以:

class A {};
typedef A B;
std::cout << typeid(B).name();

打印" A类"。一个未命名的对象不能给出"真名"。但是,使用typedefdecltype。可以创建一个新名称。如果此名称用于创建对象。typeid().name将打印新分配的名称。如果对象未命名以" true Name"名称开始。


方案:

  1. 区别在于,在第一个您使用私人声明的名称中。这是非法的。这与类型扣除的不同方式工作有关。正如斯科特·迈耶斯(Scott Meyers)在这里解释的那样。由于公共功能呼叫提供了此类型,因此返回类型是公共的。但是,Bar本身不是公开的。这是一个很小的差异,但这就是原因。

    这只是设计中已经做出的决定。这是有道理的,有时您只希望在返回时使用结构。

  2. 也是如此。没有区别,但是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条)仅一旦名称查找和功能过载分辨率(如果适用)已成功。只有在名称查找后,功能过载分辨率(如果适用)和访问检查成功的属性是该名称声明在表达式处理中进一步使用的属性

autodecltype(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名称,您的代码将愉快地编译。

您的问题链接解释了很多,但作为对那里写的内容的补充...

  1. 主要区别在于,在第二行auto b=...中,您让编译器推断出表达式的类型。您无法指定类型,因为该类型的名称被隐藏。类型是可用的(至少来自编译器)

  2. 您可以公开公开该类型的名称,因此可以使用。

这是一个很好的答案https://stackoverflow.com/a/13532882/3037915

尝试回答标题中的问题,您可以将类型键入形状和类型的名称,作为您用来指代特定形状的名称。即使隐藏了"形状"的名称,形状仍然存在并且可以使用。