代码之家  ›  专栏  ›  技术社区  ›  Akaanthan Ccoder

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

  •  3
  • Akaanthan Ccoder  · 技术社区  · 16 年前

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

    i.e MyClass ObjA;
    

    ObjA调用memberfunc()。

    我们可以通过编程在memberfunc()中得到这个名字'ObjA'吗?

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

    编辑:

    如果这在c++中是不可能的,那么在其他编程语言中是可能的吗?

    编辑2

    对这个问题作了一些修改,因为很少有人不能解释。

    7 回复  |  直到 16 年前
        1
  •  8
  •   Marcelo Cantos    16 年前

    这里有几个问题:

    1. 对象不调用任何东西,代码调用。
    2. 对象没有名称。一个对象通常分配给一个变量,通常分配给多个变量,通常根本不分配任何变量,例如数组元素。
    3. 访问调用堆栈 可以 让您了解拥有调用您的代码的调用类,但即使这样,通常也需要一个超越大多数语言的反射功能的自省级别。

    我见过C++库破解堆栈(顺便说一下,这是非常不可移植的),因此代码可以像“谁叫我”那样来计算数据,但我多年来没有使用过这些东西。

        2
  •  3
  •   Péter Török    16 年前

    不,没有办法。C++没有反射,它 将

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

        3
  •  3
  •   Gabe Timothy Khouri    16 年前

    不,对象名只存在于源代码中。一旦编译,对象引用就是一个内存偏移量。如果你想知道变量名,你必须在某个地方有一个字符串来描述它。

    在具有内省机制(如反射)的语言中,获取变量名的功能非常有限,而且根本不广泛可用。即使是在C#——一种娘娘腔的男人语言——中,要得到一个变量名,你也需要使用一个奇怪的C#3.5特性,称为投影,然后跳转通过hoops来提取它。即使这样,你也必须为它编程——它不仅在代码的任何一点上都是可用的。

    经过一番思考后,您提出的问题(从成员函数获取对象的名称)是

    class ObjA {
    public:
      void memberfunc() {
        //confused??? instance1 or instance2?
      }
    };
    
    //main
    ObjA instance1;
    ObjA* instance2 = &instance1;
    instance2->memberfunc();
    

    在上面的示例中,我们有一个 ObjA 磨尖 这里比较宽松)。这些变量完全超出了对象的任何可想象的控制范围,因此不可能获取它们,即使获取变量名的工具可用。

    在C语言中,可以使用匿名类和反射来获取变量名。这样做的方法是相当尴尬的,如果你试图用这个来向某人展示一些东西,现在就放弃,因为你们都会感到困惑。该技术使用了一些新的功能,包括匿名类、投影、扩展方法和反射。

    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"
      }
    }
    
        4
  •  0
  •   radman    16 年前

    好吧,你的问题似乎有点不清楚,但假设你想在它的成员函数中打印出类的名称,这是很有可能的。

    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();
    
    }
    
        5
  •  0
  •   dbr    16 年前

    你的问题不是很清楚-你想知道这个方法所属的对象吗?或者调用成员函数的方法的名称?哦,还有别的吗。。?

    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()
    

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

    同样,您想做这样一件事的情况很少,通常仅限于代码覆盖工具和调试器之类的内省繁重的事情

        6
  •  0
  •   ezpz    16 年前

    正如其他文章所述,在运行时没有直接的方法来访问您在代码中选择的变量名标识符——从机器的角度来看根本不需要它。然而,在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
    

    你可以在C++中做类似的事情 typeid ,但并不确切。例如:

    #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;
    }
    
        7
  •  0
  •   B Johnson    16 年前

    #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;
    }