在运行时更改类变量?

时间:2011-10-16 08:48:49

标签: oop class reflection runtime structure

让我想一想我想做什么:我有一个名为student的结构或类,它包含像

这样的变量
int roll_no

int reg_no

如果用户希望在运行时添加char name这样的新变量,该如何完成?

1 个答案:

答案 0 :(得分:1)

基于单词“Structure”和变量声明,我猜这个问题是关于C的某些风格。完全这样做取决于语言,但是一般规则,如果编译语言(例如C / C ++,Java),这是不可能的。如果语言被解释(例如Python),这可能是可能的,如下所示:

class MyObj:
  message = "Hi there"

a = MyObj()  # Creating a new instance variable
a.name = "Bill" # Adding a new attribute

我们已将name属性添加到a对象,而不是整个类。我不确定你是怎么为整个班级做的。

但实际上,你问题的答案是“不要”。您应该考虑您的程序和您正在使用的对象,以了解您将要和不需要的字段。如果您希望在程序中的某个位置有一个名称字段,请将其放在类声明中。如果您不希望它具有对象创建的值,请使用合理的默认值null

修改

根据您的评论,有几种方法可以解决这个问题。我仍然不完全清楚你想要什么,但我认为其中一个案例应该涵盖它。在我所知的语言中,Python在运行时是最灵活的:

的Python

在Python中,类只是另一种对象。类变量(也可以查看this question)属于类本身,并且由您创建的任何实例继承:

class MyObj:
  a = 2            # A class variable
  b = "a string"   # Another one

ObjInstance = MyObj()  # Creating an instance of this class
print ObjInstance.a  # Output: "2"    
ObjInstance.a = 3  # You can access and change the value of class variables *for this instance*    
print MyObj.a, ObjInstance.a  # Outputs "2 3".  We've changed the value of a for the instance

MyObj.c = (3,4)  # You can add a new class variable at runtime    
# Any instance objects inherit the new variable, whether they already exist or not.
print MyObj.c, ObjInstance.c  # Outputs "(3, 4) (3, 4)"

您可以使用此属性向类的每个实例添加属性,但在更改它们之前它们都将具有相同的值。如果要仅将属性添加到一个实例,可以执行以下操作:

ObjInstance.d = "I belong to ObjInstance!"
print ObjInstance.d   # Output: "I belong to ObjInstance!"
print MyObj.d  # Throws "AttributeError: class MyObj has no attribute 'd'"

使用Python的一个缺点是它可能有点慢。如果你想使用一种编译语言,它会稍微复杂一点,并且获得与上面提到的相同的功能将更加困难。但是,我认为这是可行的。这是我在Java中的表现。 C / C ++中的实现会有所不同。

爪哇

Java的类属性(和方法)被调用(和声明)static

class MyObj {
  public static int a = 2;
  public static String b = "a string";
}
通常通过类名访问

static个变量,就像在Python中一样。你可以通过一个实例获取它们,但我相信它会产生一个警告:

System.out.println(MyObj.a);   //Outputs "2"
MyObj ObjInst = new MyObj();
System.out.println(ObjInst.a);  //Outputs "2" with a warning.  Probably.

您无法在运行时向Java对象添加属性:

ObjInst.c = "This will break";  // Throws some exception or other

但是,您可以使用HashMap属性static,可以在运行时添加条目,这些属性就像属性一样。 (这正是Python在幕后所做的。)例如:

class MyObj {
  private HashMap<String, Object> att = new HashMap<String, Object>();

  public void setAttribute(String name, Object value) {
    att.put(name, value);
  }

  public Object getAttribute(String name) {
    return att.get(name);
  }     
}

然后你可以做以下事情:

ObjInst.setAttribute("name", "Joe");
System.out.println(ObjInst.getAttribute("name"));

请注意,我上面没有声明att static,因此在这种情况下MyObj类的每个实例都有此属性,但类本身才不是。如果我已将其声明为static,则该类本身将具有此哈希的一个副本。如果你想变得非常花哨,可以将两种情况结合起来:

class MyObj {
  private static HashMap<String, Object> classAtt = new HashMap<String, Object>();
  private HashMap<String, Object> instAtt = new HashMap<String, Object>();

  public static void setClassAttribute(String name, Object value) {
    classAtt.put(name, value);
  }

  public void setInstAttribute(String name, Object value) {
    instAtt.put(name, value);
  }

  public Object getAttribute(String name) {
    // Check if this instance has the attribute first
    if (this.instAtt.containsKey(name) {  
      return instAtt.get(name);
    }
    // Get the class value if not
    else {
      return classAtt.get(name);
    }
  }     
}

我遗漏了一些细节,比如处理HashMap没有你要求的价值的情况,但你可以弄明白该做什么。最后一点,您可以使用dict在Python中完成我在Java中所做的工作,如果属性名称是字符串,那么这可能是个好主意。您可以在Python中将属性添加为字符串,但这有点难;查看有关反射的文档以获取更多信息。

祝你好运!