本机 C++ 表达式的限制
更新:2007 年 11 月
本主题适用于:
版本 |
Visual Basic |
C# |
C++ |
Web Developer |
---|---|---|---|---|
速成版 |
仅限本机 |
|||
标准版 |
仅限本机 |
|||
专业团队版 |
仅限本机 |
表格图例:
适用 |
|
不适用 |
|
默认情况下隐藏的一条或多条命令。 |
当在调试器窗口中输入 C/C++ 表达式时,将受到下列常规限制:
访问控制
调试器可以访问所有的类成员而不用考虑访问控制。可以检查任一类对象成员,包括基类和嵌入成员对象。
不明确的引用
如果调试器表达式引用不明确的成员名称,必须使用类名称来限定它。例如,如果 CObject 是 CClass 实例,后者从 AClass 和 BClass 二者中继承了名为 expense 的成员函数,则 CObject.expense 是不明确的。可以按如下方式化解多义性:
CObject.BClass::expense
若要化解多义性,表达式计算器应用关于成员名称的正常域控制规则。
匿名命名空间
本机 C++ 表达式计算器不支持匿名命名空间。例如,假定您具有下列代码:
#include "stdafx.h"
namespace mars
{
namespace
{
int test = 0;
}
}
int main()
{
// Adding a watch on test does not work.
mars::test++;
return 0;
}
本示例中,唯一一种监视符号 test 的方式是使用修饰名:
(int*)?test@?A0xccd06570@mars@@3HA
构造函数、析构函数和转换
不能使用要求构造临时对象的表达式显式或隐式地为对象调用构造函数或析构函数。例如,下列表达式显式调用构造函数并导致错误信息:
Date( 2, 3, 1985 )
如果转换的目标是类,则不能调用转换函数。这种转换涉及到构造对象。例如,如果 myFraction 是 CFraction 的实例,后者定义了转换函数运算符 FixedPoint,下列表达式导致错误:
(FixedPoint)myFraction
但是,如果转换的目标是内置类型,则可以调用转换函数。如果 CFraction 定义转换函数 operator float,在调试器中以下表达式是合法的:
(float)myFraction
可以调用返回对象或声明局部对象的函数。
不能调用 new 或 delete 运算符。下列表达式在调试器中不能运行:
new Date(2,3,1985)
继承
当使用调试器显示具有虚拟基类的类对象时,为每个继承路径显示虚拟基类的成员,即使只存储了那些成员中的一个实例也是如此。
虚函数调用将被表达式计算器正确地处理。例如,假定类 CEmployee 定义虚拟函数 computePay,该函数在从 CEmployee 继承的类中重新定义。可以通过指向 CEmployee 的指针调用 computePay,并执行正确的函数:
empPtr->computePay()
可以将指向派生类对象的指针转换为指向基类对象的指针。不允许反向转换。
内部和内联函数
调试器表达式不能调用内部或内联函数,除非该函数至少作为正常函数出现一次。
数值常数
调试器表达式可以使用八进制、十六进制或十进制格式的整数常数。默认情况下,调试器需要十进制常数。此设置可以在“调试”选项卡的“常规”页上更改。
可以使用前缀或后缀符号表示另一基中的数字。下表显示了可以使用的格式。
语法 |
示例(十进制 100) |
基数 |
---|---|---|
数字 |
100 或 64 |
十进制或十六进制,具体取决于当前的设置。 |
0数字 |
0144 |
八进制(以 8 为基数) |
0n数字 |
0n100 |
十进制(以 10 为基数) |
0x数字 |
0x64 |
十六进制(以 16 为基数) |
数字h |
64h |
十六进制(以 16 为基数) |
运算符函数
调试器表达式可以隐式或显式地调用类的运算符函数。例如,假设 myFraction 和 yourFraction 都是定义 operator+ 的类的实例。可以使用下列表达式显示这两个对象的和:
myFraction + yourFraction
如果将运算符函数定义为友元函数,则可以使用与调用成员函数相同的语法隐式调用它,或者显式调用它,如:
operator+( myFraction, yourFraction )
与一般函数一样,不能调用带有要求转换(涉及到对象构造)的参数的运算符函数。
调试器不支持同时具有常量和非常量版本的重载运算符。带有 const 和非 const 版本的重载运算符常用在标准模板库中。
重载
如果存在精确匹配或者匹配不要求涉及对象构造的转换,则调试器表达式可以调用重载函数。例如,如果函数 calc 将 CFraction 对象作为参数,并且 CFraction 类定义接受整数的单一参数构造函数,则下列表达式将导致错误:
calc( 23 )
即使存在将整数转换为 calc 期望的 CFraction 对象的合法转换,但这样的转换涉及到对象的创建,因此不受支持。
优先级
在调试器表达式中,C++ 范围运算符 (::) 比其在源代码中具有更低的优先级。在 C++ 源代码中,该运算符具有最高的优先级。在调试器中,其优先级介于基数与后缀运算符(->、++、--)和一元运算符(!、&、* 及其他)之间。
符号格式
如果符号所在的模块是用完全调试信息(/Zi 或 /ZI)编译的,则输入的包含符号的调试器表达式与源代码中使用的格式相同。如果输入的表达式包含公共符号(即在库中或者在用 /Zd 编译的模块中可以找到的符号),则必须使用符号的修饰名(即在对象代码中使用的格式)。有关更多信息,请参见 /Z7、/Zd、/Zi、/ZI(调试信息格式)。
使用 LINK /MAP 选项可以获得所有修饰和未修饰格式的名称列表。有关更多信息,请参见 /MAP(生成映射文件)。
名称修饰是用于强制类型安全链接的机制。这意味着只有拼写、大小写、调用约定和类型精确匹配的名称和引用才链接在一起。
用 C 调用约定声明(使用 _cdecl 关键字显式或隐式声明)的名称以下划线 (_) 开头。例如,函数 main 可显示为 _main。声明为 _fastcall 的名称以 @ 符号开头。
对于 C++,修饰名除了对调用约定进行编码外还对符号类型进行编码。这种格式的名称会很长而且难以读取。该名称以至少一个问号 (?) 开头。对于 C++ 函数,修饰包括函数范围、函数参数的类型和函数返回类型。
类型强制转换
如果转换为类型,调试器必须已知该类型。在程序中必须有该类型的另外一个对象。不支持使用 typedef 语句创建的类型。