成员函数如何以编程方式*知道调用它的“对象名称”?

时间:2010-05-21 10:27:00

标签: c++ oop programming-languages object

假设我们有一个MyClass类和一个memberfunc()。 为这个MyClass创建了一个对象,比如ObjA。

i.e MyClass ObjA;

ObjA调用memberfunc()。

我们可以以编程方式在memberfunc()中获得此名称'ObjA'吗?

注意:我知道如何使用RTTI(运行时类型识别)获取对象的类型,即“MyClass”,下面的radman也解释了相同的内容。

修改

如果在c ++中这是不可能的,是否可以使用任何其他编程语言?

EDIT2

对这个问题进行了一些修改,因为很少有人无法解释。

7 个答案:

答案 0 :(得分:8)

这里有几个问题:

  1. 对象不会调用任何东西,代码也可以。
  2. 对象没有名称。通常将对象分配给变量,通常分配给多个变量,通常根本不分配变量,例如数组元素。
  3. 访问调用堆栈可能让您了解拥有调用您的代码的调用类,但即使这通常需要一定程度的内省超出大多数的反射设施语言。
    • Python是一个值得注意的例外。它可以给你堆栈走路和找出很多有趣的东西。 C ++不会。
  4. 我已经看到C ++库破解了堆栈(顺便说一句,这是非常不便携的),因此让代码能够像“谁叫我?”这样的东西。但是我已经多年没用过那些东西了。

答案 1 :(得分:3)

不,没有办法。 C ++没有反射, 可能会使这成为可能。在第二个想法,甚至是例如反射设施。 Java没有此功能。

C ++直接编译为机器代码,不再包含源代码中的任何标识符。您当然可以将“变量名称”存储在成员字段中(前提是该对象在单个名称下引用...)。

答案 2 :(得分:3)

不,对象名称仅存在于源代码中。编译后,对象引用只是一个内存偏移量。如果你想知道变量名,你必须在某处描述它。

在具有内省机制(例如Reflection)的语言中获取变量名称的工具非常有限,并且根本没有广泛使用。即使在C#(少女语言)中,要获得变量名称,您需要使用一种称为投影的古怪C#3.5特征,然后跳过箍来提取它。即使这样,你也必须为它编程 - 它不会在代码的任何一点都可用。

在一些人认为你正在构建的问题 - 从成员函数中获取对象的名称 - 理论上不可能。请考虑以下情况:

class ObjA {
public:
  void memberfunc() {
    //confused??? instance1 or instance2?
  }
};

//main
ObjA instance1;
ObjA* instance2 = &instance1;
instance2->memberfunc();

在上面的示例中,我们有一个ObjA实例,其中有两个变量指向它(我在这里使用了术语指向而非常松散)。这些变量完全超出对象的任何可想象的控制范围,因此即使获得变量名称的工具可用,也无法获得它们。

在C#中,您可以使用匿名类和Reflection来获取变量名。这样做的方法很尴尬,如果你试图用它来向别人展示一些东西,现在就放弃,因为你们两个都会感到困惑。该技术使用了一些主流编程新功能,包括匿名类,投影,扩展方法和反射。

public static class Extensions {
  public static string GetFirstPropertyName(this object obj) {
    return obj.GetType().GetProperties()[0].Name;
  }
}

public class Program {
  public static void Main() {
    int intVal = 5;
    var name = (new {intVal}).GetFirstPropertyName();
    //name=="intVal"
  }
}

答案 3 :(得分:0)

那么你的问题似乎有点不清楚,但假设你想在其中一个成员函数中打印出类的名称,那很可能。

您需要使用的是typeid命令。这在运行时为类类型的对象提取了一个接近人类可读的名称。但是你不能依赖这个名称在不同平台上保持一致,即你得到的名称可能因平台而异(我从下面的示例代码得到的是'4ObjA'。

#include <iostream>
#include <typeinfo>
class ObjA
{
public:
  void memberfunc()
  {
    std::cout << typeid(*this).name() << std::endl;

  }
};

int main(int argc, char **argv)
{
  ObjA obj;
  obj.memberfunc();

}

答案 4 :(得分:0)

您的问题并不完全清楚 - 您想知道该方法所属的对象吗?或者调用成员函数的方法的名称? Oo别的什么..?

在大多数面向对象语言中,您可以非常轻松地获取当前类的名称:

class Myclass(object):
    def memberfunc(self):
        print self.__class__.__name__

obja = Myclass()
obja.memberfunc() # prints Myclass

你不能明智地将obja标识符作为名称(几乎所有语言),我不明白为什么你想要(在这种情况下,你会使用某种类型的键/值映射)

如果要获取调用该方法的方法的名称,则必须检查调用堆栈,例如在Python中使用inspect方法:

import inspect

class Myclass(object):
    def memberfunc(self):
        current_call = inspect.stack()[0]
        previous = inspect.stack()[1]
        print previous[3]

def somefunc():
    obja = Myclass()
    obja.memberfunc() # prints somefunc

somefunc()

我想这在其他语言中并不那么容易

同样,你想要做这种事情的情况很少见,通常仅限于内省重要的事情,如代码覆盖工具和调试器

答案 5 :(得分:0)

正如其他帖子所述,没有直接的方法来访问您在运行时在代码中选择的变量名称标识符 - 从机器的角度来看根本不需要它。但是,在Ruby中,根据结构来了解调用者的详细信息是微不足道的:

class Foo
   def foo
      puts self.class
   end
end

class Bar < Foo
end

f = Foo.new
b = Bar.new

f.foo #=> Foo
b.foo #=> Bar

您可以使用typeid在C ++中执行类似操作,但这并不完全正确。例如:

#include <iostream>
class Foo {
    public:
        void foo () { std::cout << typeid(this).name() << std::endl; }
};

int main () {
    Foo f;
    f.foo ();  // on my system returns P3Foo
    return 0;
}

答案 6 :(得分:0)

这有点像黑客,但您可以使用宏来存储类标识符名称。这就是我的意思:

#include <iostream>
#include <string>

#define createMyClass(x) MyClass x("x")

class MyClass{
    string _name;
    MyClass( const string& name ) : _name(name){}
    memberfunc(){
        std::cout << "Name: " << _name << std::endl;
    }
}

int main (int argc, char **argv) {
    createMyClass( ObjA );
    ObjA.memberfunc(); // prints the name
    return 0;
}