this->func() 和 func() 的语法之间有什么细微差别吗?
Are there any nuance differences between the syntax this->func() and func()?
如果我的 class 有虚函数,没有自由函数,this->func()
和 func()
之间有什么区别吗
class Base {
virtual void A() { std::cout << "Base" << std::endl; };
void B() { this->A(); };
void C() { A(); };
};
class Derived : public Base {
virtual void A() { std::cout << "Derived" << std::endl; };
void B2() { this->A(); };
void C2() { A(); };
};
方法B()
和C()
的执行有什么区别吗? B2()
和 C2()
方法呢?
在您发布的示例中,两种语法之间没有区别。它们完全相同。
有两种情况是有区别的。一种是如果您有一个模板 class 继承自依赖于模板参数的类型。例如:
template <typename T> class Base {
public:
void doSomething() const {
std::cout << "Do ALL the things!" << std::endl;
}
};
template <typename T> class Derived: public Base<T> {
public:
void doSomethingElse() const {
doSomething(); // Error!
this->doSomething(); // Okay
}
};
这里,由于 Derived<T>
继承自 Base<T>
类型,它依赖于模板参数,名称查找在 two-step 过程中完成。如果您使用非限定语法调用 doSomething
,那么编译器将不知道查看 Base<T>
来找到它,并将报告错误。但是,如果你说 this->doSomething()
,它知道你正在调用一个成员函数,并且最终会弄清楚它应该在 Base<T>
.
中查找
另一种情况是在函数内部声明了一个与成员函数同名的局部对象。例如:
class ThisIsSillyDontDoThisLikeSeriouslyDont {
public:
void doSomething() const {
std::cout << "Do ALL the things!" << std::endl;
}
void weirdFunction() const {
auto doSomething = [] {
std::cout << "I'm afraid there's nothing to be done" << std::endl;
};
doSomething(); // Calls the local function
this->doSomething(); // Calls the member function
}
};
第二种情况非常罕见,我从未见过,我什至可以说它的编码风格非常糟糕。
不过,除了这些罕见的情况,使用和不使用 this->
作为前缀调用自己的成员函数没有区别。
通常没有区别,因为标准要求调用形式为 A()
的成员函数等同于 (*this).A()
。一些不同的例子是:
- 如果
A
有block-scope声明,那么A()
会调用声明的函数,而this->A()
会一直调用成员函数。参见 http://coliru.stacked-crooked.com/a/ea49916562bd4371
- 如果
A
是依赖基 class 的成员,那么尝试将其称为 A()
将失败; this->A()
需要将名称查找推迟到实例化时间。
关于 Non-static member functions 的 Cppreference 指出模板定义的上下文存在差异:
Within the body of a non-static member function of X, any
id-expression E (e.g. an identifier) that resolves to a non-type
non-static member of X or of a base class of X, is transformed to a
member access expression (*this).E (unless it's already a part of a
member access expression). This does not occur in template definition
context, so a name may have to be prefixed with this-> explicitly to
become dependent.
所以在你的例子中它没有什么不同,但在其他情况下,例如定义模板时,可能会。
如果我的 class 有虚函数,没有自由函数,this->func()
和 func()
class Base {
virtual void A() { std::cout << "Base" << std::endl; };
void B() { this->A(); };
void C() { A(); };
};
class Derived : public Base {
virtual void A() { std::cout << "Derived" << std::endl; };
void B2() { this->A(); };
void C2() { A(); };
};
方法B()
和C()
的执行有什么区别吗? B2()
和 C2()
方法呢?
在您发布的示例中,两种语法之间没有区别。它们完全相同。
有两种情况是有区别的。一种是如果您有一个模板 class 继承自依赖于模板参数的类型。例如:
template <typename T> class Base {
public:
void doSomething() const {
std::cout << "Do ALL the things!" << std::endl;
}
};
template <typename T> class Derived: public Base<T> {
public:
void doSomethingElse() const {
doSomething(); // Error!
this->doSomething(); // Okay
}
};
这里,由于 Derived<T>
继承自 Base<T>
类型,它依赖于模板参数,名称查找在 two-step 过程中完成。如果您使用非限定语法调用 doSomething
,那么编译器将不知道查看 Base<T>
来找到它,并将报告错误。但是,如果你说 this->doSomething()
,它知道你正在调用一个成员函数,并且最终会弄清楚它应该在 Base<T>
.
另一种情况是在函数内部声明了一个与成员函数同名的局部对象。例如:
class ThisIsSillyDontDoThisLikeSeriouslyDont {
public:
void doSomething() const {
std::cout << "Do ALL the things!" << std::endl;
}
void weirdFunction() const {
auto doSomething = [] {
std::cout << "I'm afraid there's nothing to be done" << std::endl;
};
doSomething(); // Calls the local function
this->doSomething(); // Calls the member function
}
};
第二种情况非常罕见,我从未见过,我什至可以说它的编码风格非常糟糕。
不过,除了这些罕见的情况,使用和不使用 this->
作为前缀调用自己的成员函数没有区别。
通常没有区别,因为标准要求调用形式为 A()
的成员函数等同于 (*this).A()
。一些不同的例子是:
- 如果
A
有block-scope声明,那么A()
会调用声明的函数,而this->A()
会一直调用成员函数。参见 http://coliru.stacked-crooked.com/a/ea49916562bd4371 - 如果
A
是依赖基 class 的成员,那么尝试将其称为A()
将失败;this->A()
需要将名称查找推迟到实例化时间。
关于 Non-static member functions 的 Cppreference 指出模板定义的上下文存在差异:
Within the body of a non-static member function of X, any id-expression E (e.g. an identifier) that resolves to a non-type non-static member of X or of a base class of X, is transformed to a member access expression (*this).E (unless it's already a part of a member access expression). This does not occur in template definition context, so a name may have to be prefixed with this-> explicitly to become dependent.
所以在你的例子中它没有什么不同,但在其他情况下,例如定义模板时,可能会。