对象名在 C++ 中包含什么?

What do Objectname holds in C++?

提问人:infinull 提问时间:8/3/2023 最后编辑:UpAndAdaminfinull 更新时间:8/7/2023 访问量:119

问:

尽管C++和java是两种不同的语言。他们有很多共同点

在 Java 中这些对象包含一个引用,即:

class Cls
{
    //some fields 
    //some methods

    public static void main(String args[])
    {
        Cls obj = new Cls();
        System.out.println(obj);
    }
}

输出它给出的输出类似于这样:Cls@372f7a8d

同样地

在 C++ 中

class Cls
{
    //some var
    //some methods
}

int main()
{
    Cls obj;
    std::cout << obj;
}

错误它给出一个错误no operator "<<" matches these operands

在 C++ 中,一切都归结为 变量(保存地址、值或只是对另一个变量的引用) 或某些函数(用户定义的函数,关键字或运算符) PS:如果我错了,请纠正我

我知道打印对象名称似乎毫无意义,但是..

我只是想知道java中的objnames是否包含对该对象的引用,那么C++中的objectnames包含什么(它是一个地址?,一个值?还是更复杂的东西?㞖。。有什么方法可以在控制台中打印它。

提前致谢.

Java C++ 对象

评论

5赞 Richard Critten 8/3/2023
" C++ 中的 objectnames ...“ 是为编译器和程序员准备的 - 它们在运行时不存在。另请参阅 C++ 对象
8赞 Pete Becker 8/3/2023
在 Java 中,每个类都派生自 ,而打印引用以打印其地址。在 C++ 中没有 ,没有“对象名称”,也没有默认打印。如果要显示的内容,则必须编写一个流插入器。不要试图将你对 Java 的了解应用到 C++ 中。objectobjectobjectCls
1赞 tadman 8/3/2023
C++ 比 Java 低级得多,你经常会发现 Java 的许多便利,比如能够以调试形式转储任意对象,根本不存在。
3赞 8/3/2023
您应该注意,当您通过以下方式打印 Java 对象时,会调用 objects 方法来创建该输出。这在 Object 类中默认为 <Classname>@<hashcode>,而哈希码又默认为使用内存地址的本机 jvm 实现。但是没有通过 system.out.println 自动打印的“对象名称”。如果创建一个类并重写 toString 方法以始终返回,则通过 System.out.print 打印该类的任何对象将始终导致打印该 String。System.out.printlntoString()"Cowabanga Homies!"
2赞 molbdnilo 8/4/2023
这些语言的共同点远没有你想象的那么少。不要被句法上的相似性所迷惑。

答:

3赞 Jerry Coffin 8/3/2023 #1

在 C++ 中,对象的名称通常直接引用保存值的存储。如果您想要一个引用或地址,请显式创建:

Cls c;            // c is the actual object
auto & rc = c;    // rc is a reference to c
auto * pc = &c;   // pc holds the address of c

不过,这些都与打印对象的方式没有太大关系。通常通过使运算符重载来做到这一点:<<

#include <iostream>

class Cls {
    int x;
    int y;
public:

   Cls(int x, int y) : x(x), y(y) {}

    friend std::ostream &operator<<(std::ostream &os, Cls const &c) { 
        return os << "(" << c.x << ", " << c.y << ")";
    }
};

int main() {
    Cls x(1, 3);
    std::cout << x << "\n";
}

生成如下输出:

(1, 3)

operator<<通常采用对要打印的对象的引用。不过,这样做通常是为了避免制作不必要的副本,而不是因为它是绝对必要的。某些类型也不允许复制,在这种情况下,必须通过引用传递。

评论

0赞 user17732522 8/4/2023
@FrançoisAndrieux “标识符无法更改标识的对象”:这也是不正确的。每次控制通过其定义时,自动存储持续时间变量都引用不同的对象(大致)。目前,该标准本身并没有很好地描述这种关系。placement-new 也可以更改名称所指的对象。
0赞 François Andrieux 8/4/2023
@user17732522我不同意其中一些情况,但我没有想过要放置新的。无论如何,我认为“价值”一词在这里被误用了,标识符指的是一个实体,而不是它的价值。某些标识符甚至不引用可以具有值的实体,例如函数的名称。
0赞 François Andrieux 8/4/2023
@user17732522 第二,难道不应该使用新表达式生成的指针而不是原始标识符吗?
0赞 user17732522 8/4/2023
@FrançoisAndrieux 如果新对象可以透明地替换为旧对象,则引用旧对象的所有指针、引用和名称都将引用新对象。因为这要求类型在 cv 限定符之前相同,所以仅将两个对象视为相同并没有太大的实际区别,即使这在形式上是不正确的。
1赞 user17732522 8/4/2023
@FrançoisAndrieux 该名称表示类似于变量或函数 (eel.is/c++draft/basic#pre-5.sentence-3) 的实体,但作为表达式,如果它表示变量,则它是一个左值,其结果是运行时与变量对应的对象(当重新输入范围时,该对象可能不同)。不幸的是,该标准目前将变量混为编译时实体和在运行时从这些实体“实例化”的对象,如 eel.is/c++draft/basic#pre-6 所示。
0赞 chamip 8/4/2023 #2

“<<”是一个 ostream 运算符,用于输出 base-out 类型的数据。现在你定义了一个类,你应该重载<<运算符(也许这对初学者来说很难)。事实上,你如何定义<<,你输出什么。

#include <iostream>

class Cls
{
    //some var
    //some methods
    private:
        int a;
        float b;
    public:
        void f1();
        Cls():a(0), b(0.0) {};
        friend std::ostream &operator<<(std::ostream &os, const Cls &cls) {
            return os << cls.a << " " << cls.b << std::endl;
        };
};

int main()
{
    Cls obj;
    std::cout << obj;
}
0赞 vnagy 8/7/2023 #3

“尽管C++和java是两种不同的语言。他们有很多共同点”

虽然这两种语言在语法上相似,但它们的工作方式却有很大不同。一种编译为本机代码,而另一种是编译为字节码的托管语言,然后由 VM 执行(VM 可以自由地将其重新编译为本机代码或其他任何内容...... 你可以在 Java 中摆脱这一点的原因:

System.out.println(obj);

是因为 Java 就是这样设计的。java 中的每个类都继承自 并且该类有一个具有默认实现的方法,该方法生成字符串,如下所示:java.lang.ObjecttoString()

getClass().getName() + '@' + Integer.toHexString(hashCode())

但请注意,这不是您所说的“对象名称”。根据 java 文档,它是

简明扼要但内容丰富的表示,易于阅读。建议所有子类都重写此方法

另请注意,默认实现如下所述:hashCode

在合理可行的情况下,类 Object 定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常是通过将对象的内部地址转换为整数来实现的,但 Java™ 编程语言不需要这种实现技术。

这意味着,如果 toString 和 hashCode 实现都保持不变,那么您最终得到的内容确实包含类名和实例地址的一些派生,但后者不是实现要求。

所以简而言之,它不是一个通用的“对象名称”机制。建议大多数子类重写此方法。现在总结一下,就 Java 而言

System.out.println(obj);

只需调用并打印返回的任何字符串。没有魔术发生,每个细节都在语言的实现中描述。obj.toString()

在C++的情况下,语言规范没有像Java的.没有一个永远存在的基类使运算符<<用一些默认实现重载,所以你不能只使用它......java.lang.Object

库开发人员可能会决定实现或使用类似于 Java 的基类(可能具有默认的<<运算符),并可能尝试强制所有其他类必须从该基类继承。但这完全留给开发人员。

在 C++ 中,您可以使用如下内容:

std::cout << "Memory address: " << static_cast<void*>(myPointer) << std::endl;

打印实例的内存地址。它也适用于,因此您可以创建自己的默认 toString 实现,如果这是您想要的。this

这两种语言截然不同的原因比这个答案中详细介绍要复杂一些。