typedef别名的析构函数

Fel*_*ara 22 c++ destructor typedef language-lawyer

#include <iostream>

struct A { ~A(); };
A::~A() {
    std::cout << "Destructor was called!" << std::endl;
}

typedef A AB;
int main() {
    AB x;
    x.AB::~AB(); // Why does this work?
    x.AB::~A();
}
Run Code Online (Sandbox Code Playgroud)

上述程序的输出是:

Destructor was called!
Destructor was called!
Destructor was called!
Run Code Online (Sandbox Code Playgroud)

我假设前两行属于用户析构函数调用,而第三行是由于在退出main函数范围时调用析构函数.

根据我的理解,typedef是类型的别名.在这种情况下AB是别名A.

为什么这也适用于析构函数的名称?非常感谢对语言规范的引用.

编辑:这是在macOS High Sierra版本10.13.3上使用Apple LLVM版本9.1.0(clang-902.0.39.1)编译的.

eer*_*ika 21

为什么这也适用于析构函数的名称?

因为标准说:

[class.dtor]

在显式的析构函数调用中,析构函数由〜后跟一个type-name或decltype-specifier来指定,该类型名称或decltype-specifier表示析构函数的类类型....

typedef别名是一个类型名称,它表示与类本身的类型名称相同的类.

该规则甚至有一个澄清的例子:

struct B {
  virtual ~B() { }
};
struct D : B {
  ~D() { }
};

D D_object;
typedef B B_alias;
B* B_ptr = &D_object;

void f() {
  D_object.B::~B();             // calls B's destructor
  B_ptr->~B();                  // calls D's destructor
  B_ptr->~B_alias();            // calls D's destructor
  B_ptr->B_alias::~B();         // calls B's destructor
  B_ptr->B_alias::~B_alias();   // calls B's destructor
}
Run Code Online (Sandbox Code Playgroud)

有关名称查找的进一步说明,还有一个适用于该问题的示例:

[basic.lookup.qual]

如果伪析构函数名称([expr.pseudo])包含嵌套名称说明符,则类型名称将在nested-name-specifier指定的作用域中作为类型查找.同样,在表单的qualified-id中:

nested-name-specifieropt class-name :: ~class-name

第二个类名在与第一个类相同的范围内查找.[例如:

struct C {
  typedef int I;
};
typedef int I1, I2;
extern int* p;
extern int* q;
p->C::I::~I();      // I is looked up in the scope of C
q->I1::~I2();       // I2 is looked up in the scope of the postfix-expression

struct A {
  ~A();
};
typedef A AB;
int main() {
  AB* p;
  p->AB::~AB();     // explicitly calls the destructor for A
}
Run Code Online (Sandbox Code Playgroud)

- 结束例子]


Lig*_*ica 6

因为当你写的时候你~AB()没有命名或调用析构函数.你正在写~后面类的名称和析构函数调用时自动配置为写彼此相邻的令牌的指定语义的结果.

通常这是学术性的,但在这里你明白为什么它很重要.

类似地,通过编写AB()你不是"调用构造函数",即使这看起来像一个函数调用,许多语言新手以这种方式解释代码.(当试图在没有参数推断的情况下调用模板构造函数时,这可以带来乐趣和游戏:如果不能命名构造函数,则无法提供这些参数!)

实际上,构造函数和析构函数在技术上没有名称!

这些细微差别让C++变得有趣,对吗?

  • @Eljay这就是为什么我们喜欢它^ _ ^ (2认同)