有没有办法仅使用类的对象名称作为"default"成员?

Is there a way to use only the object name of a class as a "default" member?

本文关键字:default 成员 对象 有没有      更新时间:2023-10-16

用类似的方式思考:
1.数组的裸名称与指向第一个元素的指针等效,无需指定索引0。
2.Java中的toString()使得可以在不调用任何对象方法的情况下将对象的名称用作字符串。

现在C++中有没有一种方法可以使用类对象的名称来引用它的第一个成员?考虑:

class Program
{
public:
    int id;
    char *str;
};
void function(int p)
{
//...
}

然后:

Program prog0;
function(prog0); // instead of function(prog0.id)

有什么方法可以"隐藏"成员引用吗
编辑:
为什么holyBlackCat的回答被删除了?我倾向于把它作为最好的答案——无意冒犯,马特乌兹。但他是第一个提出转换运算符的人,这个例子既完整又简单。

在C++中,这种行为将是一场灾难。如果我理解正确的话,Java试图通过搜索A中的第一个成员将A类型的对象转换为B类型的对象,即B类型或可隐式转换为B类型的成员。

C++不是这样设计的。我们喜欢写代码,这总是可以预测的。您可以实现您想要的目标,但需要付出一定的代价。

在这种情况下,最好的解决方案是转换操作员-考虑:

class Program
{
public:
  int id;
  char *str;
  operator int()
  {
    return this->id;
  }
  //You can have more than one!
  operator const char*()
  {
    return this->str;
  }
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}

现在可以进行以下操作:

Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)

价格是,如果您添加另一个int并将其放在id之前,它将不会用于转换,因为我们在运算符中明确指出,我们类的"int内容"由id表示,在进行此类转换时会考虑该成员。

然而,即使是这个简单的例子也显示了一些潜在的问题——用积分和指针类型重载函数可能会导致非常不可预测的行为。当类型同时包含指向指针和整数的转换运算符时,情况可能会变得更糟。

假设我们有以下功能:

void func(unsigned long)
{
}

我们用类型为Program的自变量调用func。您希望调用哪个转换运算符?编译器知道如何将Program转换成intconst char*,但不知道如何将其转换为unsigned long。这篇关于cppreference的文章应该可以帮助您理解隐式转换是如何工作的。


此外,正如巴里所指出的,更多无意义的构造变得可用。考虑一下这个:

int x = prog + 2

这是什么意思?不过,这是完全有效的代码。这就是为什么转换运算符应该非常小心地使用(在C++11之前的时代,有一个普遍的建议,每个类最多应该有一个这样的运算符)。

MSDN报价:

如果需要导致歧义的转换,则会生成错误。当有多个用户定义的转换可用时,或者当存在用户定义转换和内置转换时,就会出现歧义。

有时,这个问题的简单解决方案是用显式关键字标记转换运算符,因此您需要将以上调用更改为:

function_int((int)prog);
function_str((const char*)prog);

它不像以前的形式那么漂亮,但安全得多。这基本上意味着,编译器禁止使用标记为显式的运算符执行任何隐式转换。这对于避免不明确的调用非常有用,同时在代码中仍然提供一些灵活性-您仍然可以非常容易地将一种类型的对象转换为另一种类型,但您可以确定何时何地执行这些转换。

但是,某些编译器仍然不支持显式转换运算符,因为这是C++11的特性(例如,Visual C++11不支持它)。

您可以在此处阅读有关显式关键字的更多信息。

现在C++中有没有一种方法可以使用类对象的名称来引用它的第一个成员?

不,C++没有任何反射,所以没有办法真正确定"第一个成员"是什么

然而,如果你真正想要的是获得任何对象的ID,你可以只要求该对象具有以下方法:

template <typename T>
void function(const T& t) {
    int id = t.getID();
    // etc.
}

如果不了解更多关于用例的信息,就很难知道该提出什么建议。