Changing Class Variables in runtime?

2019-09-02 21:29发布

问题:

Let me give an idea of what I wish to do: I have a structure or class called student, which contains variables like

int roll_no

and

int reg_no

If the user wishes to add a new variable like char name at run time how can it be done?

回答1:

Based on the word "Structure" and the variable declarations, I'm going to guess this question is about some flavor of C. How exactly to do this will depend on the language, but as a general rule, if the language is compiled (e.g. C/C++, Java), this is not possible. If the language is interpreted (e.g. Python), this might sort of be possible, like this:

class MyObj:
  message = "Hi there"

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

Here we've added the name attribute to the a object only, and not the entire class. I'm not sure how you're go about that for the whole class.

But really, the answer to your question is "Don't". You should think about your program and the objects you're using enough to know what fields you will and won't need. If you'll want to have a name field at some point in your program, put it in the class declaration. If you don't want it to have a value on object creation, use a sensible default like null.

Edit

Based on your comments, there are a couple of ways to approach this. I'm still not entirely clear on what you want, but I think one of these cases should cover it. Of the languages I know, Python is the most flexible at runtime:

Python

In Python, a class is just another kind of object. Class variables (check out this question too) belong to the class itself, and are inherited by any instances you create:

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

You can use this to add attributes to every instance of your class, but they will all have the same value until you change them. If you want to add an attribute to just one instance, you can do this:

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'"

One drawback to using Python is that it can be kinda slow. If you want to use a compiled language it will be slightly more complicated, and it will be harder to get the same functionality that I mentioned above. However, I think it's doable. Here's how I would do it in Java. The implementation in C/C++ will be somewhat different.

Java

Java's class attributes (and methods) are called (and declared) static:

class MyObj {
  public static int a = 2;
  public static String b = "a string";
}

static variables are normally accessed through the class name, as in Python. You can get at them through an instance, but I believe that generates a warning:

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

You can't add attributes to a Java object at runtime:

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

However, you can have a HashMap attribute, static or not, which you can add entries to at runtime that act like attributes. (This is exactly what Python does, behind the scenes.) For example:

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

And then you can do things like:

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

Notice that I did not declare att static above, so in this case each instance of the MyObj class has this attribute, but the class itself does not. If I had declared it static, the class itself would have one copy of this hash. If you want to get really fancy, you can combine the two cases:

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

There are a few details I've left out, like handling the case of the HashMaps not having the value you're asking for, but you can figure out what to do there. As one last note, you can do in Python exactly what I did here in Java with a dict, and that might be a good idea if the attribute names will be strings. You can add an attribute as a string in Python but it's kind of hard; look at the documentation on reflection for more info.

Good luck!