Как член func может * программно * узнать 'имя объекта', который его вызывает? - PullRequest
3 голосов
/ 21 мая 2010

Допустим, у нас есть класс MyClass, который имеет и memberfunc (). Объект создан для этого MyClass, скажем, ObjA.

i.e MyClass ObjA;

ObjA вызывает memberfunc ().

Можем ли мы получить это имя ObjA внутри memberfunc () программно?

Примечание: я знаю, как получить тип объекта, то есть MyClass, используя RTTI (идентификация типа во время выполнения), то же самое объясняется и Радманом ниже.

EDIT:

Если это НЕ ВОЗМОЖНО в c ++, возможно ли это на любом другом языке программирования?

EDIT2

Сделал некоторые изменения в вопросе, так как немногие не смогли интерпретировать.

Ответы [ 7 ]

8 голосов
/ 21 мая 2010

Здесь есть несколько вопросов:

  1. Объекты ничего не вызывают, код делает.
  2. Объекты не имеют названия. Объект обычно присваивается переменной, часто более чем одной переменной, часто никакой переменной вообще, например элементу массива.
  3. Получение доступа к стеку вызовов может дать вам некоторое представление о вызывающем классе, которому принадлежит код, вызвавший вас, но даже для этого обычно требуется уровень самоанализа, выходящий за пределы возможностей отражения большинства языков. ,
    • Python является заметным исключением. Это может дать вам стек, чтобы идти и выяснить много интересного. C ++ не будет.

Я видел библиотеки C ++, которые взламывают стек (это, между прочим, очень непереносимо) и, таким образом, дают коду возможность разбираться со словами типа «Кто меня назвал?» но я не использовал этот материал в течение многих лет.

3 голосов
/ 21 мая 2010

Нет, имя объекта существует только в вашем исходном коде. После компиляции ссылка на объект является просто смещением памяти. Если вы хотите узнать имя переменной, у вас должна быть строка где-то, описывающая ее.

Возможность получения имени переменной в языках с механизмами самоанализа (такими как 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 для получения имени переменной. Способ сделать это довольно неловко, и если вы пытаетесь использовать это, чтобы продемонстрировать кому-то что-то, откажитесь сейчас, потому что вы оба будете сбиты с толку. В этом методе используются некоторые функции, которые являются новыми для массового программирования и включают анонимные классы, проекцию, методы расширения и 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 голосов
/ 21 мая 2010

Нет, для этого нет пути. C ++ не имеет отражения, что может сделать это возможным. На 2-й мысли, даже средства отражения, например, У Java нет этой функции.

C ++ компилируется непосредственно в машинный код, который больше не содержит никаких идентификаторов из исходного кода. Конечно, вы можете сохранить «имя переменной» в поле члена (при условии, что объект упоминается под одним именем ...).

0 голосов
/ 21 мая 2010

Это своего рода хак, но вы можете использовать макросы для хранения имени идентификатора класса. Вот что я имею в виду:

#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;
}
0 голосов
/ 21 мая 2010

Как уже говорилось в других публикациях, прямого способа доступа к идентификатору имени переменной, который вы выбираете в коде во время выполнения, нет - он просто не нужен с точки зрения машины. Тем не менее, в 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;
}
0 голосов
/ 21 мая 2010

Ваш вопрос не совсем понятен - вы хотите знать объект, которому принадлежит метод? Или имя метода, вызывающего функцию-член? Оо что-то еще ..?

В большинстве объектно-ориентированных языков вы можете легко получить имя текущего класса:

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

Я думаю, что на других языках это не так просто

Опять же, случаи, когда вы хотели бы сделать такую ​​вещь, редки, обычно ограничиваются интенсивными исследованиями, такими как инструменты покрытия кода и отладчики

0 голосов
/ 21 мая 2010

Ваш вопрос кажется немного неясным, но при условии, что вы хотите напечатать имя класса в одной из его функций-членов, это вполне возможно.

Вам необходимо использовать команду 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();

}
...