I'm trying to access different kind of structs that have changing attributes. This is one struct I'm trying to work with:
struct person {
std::string name;
std::string address;
int age;
};
I have a variable that contains "name" (the first attribute of the struct).
string n = "name";
Now if I want to access the name, it's not possible to do this:
person.n = "Same";
Is there a work around or some other way I could access struct members? I'm trying to work with different kind of structs and I have one config file where I enter the name of the members. But then I have the problem of not being able to acess the struct members if the name is saved in a variable.
A struct, also known as a class, is a type. You cannot access non static members of a type without creating an instance of a type.
For a simplified analogy, you cannot assign the int type:
int = 42; // wrong
Instead, you must create an instance of the type. You can assign that instance:
int i{};
i = 42; // ok
Similarly, you must create an instance of a class in order to access the non static members of that instance:
person.name = "Same"; // wrong
person p {};
p.name = "Same"; // ok
Related
Say I have the following simple struct in C/C++:
struct Example {
int member_a;
int member_b;
}
Now, I have an object ex of it.
For the sake of redundancy and properly relating some members, I need to assign member_b using the value of member_a. Here, as I knew the name of this object, something like this worked for me:
struct Example ex = {
.member_a = 50,
.member_b = ex.member_a * 2 // Assigning member_b in terms of member_a.
}
The above assignment works as long as int member_a is kept above int member_b in the declaration of Example struct.
I have already tried using .member_b = member_a ... and .member_b = .member_a ..., both of which failed to identify the member_a in a struct object. .member_b = <same_object_name>.member_a only seems to work with the initial definition.
Note: This all has been tried on version C18
It was a way out in case of this single struct object, but what if I do not want to use object name or if in case I'm using anonymous (unnamed) struct object? Can something like pointers or some equivalent of this exists that is compatible with C for using the relation in an object (or better if possible in struct definition itself)? Even being able to call a value of member like .member_a within Example struct shall do.
Update: If C and C++ vary a lot, please focus on a C specific solution.
C/C++ are two completely different languages if they're used modernly where C++ can take advantage of classes and the this keyword. I would assume that you want to use structs in C++ for this exact question.
If you want to just have a direct relationship for example member b is twice member, then just set them equal in the original class so that it happens during compile time.
struct Example {
int member_a;
int member_b = 2 * member_a;
};
Otherwise you have to explicitly site which struct you are using when accessing ints within it. In this case a struct doesn't have any members that strictly pertain to it and the compiler doesn't know if there's going to be a value at member_a. If you wanted to use a class then you would just set it at anytime to itself, with a function or set statement.
class Bob {
public:
int member_a;
int member_b;
private:
int double_member_a(){
member_b = 2 * member_a;
return member_b
};
};
Bob bob;
bob.member_a = 1;
bob.member_b = bob.member_a; // or bob.doubleA();
Regardless of the method you would still be changing a struct or classes values depending on that exact instance of the object so you would always have to state which one, though if you were going through any x struct of class you would just put them into a vector and do a range based for loop and access one at anytime.
I have read that constructors can inizialize only non static attribute. I have written a small code to check that and Im wondering now because the compiler dosnt show any error??? So Can I initialize static attribute and non static attribute in the constructor or not? this is my code! Thank you very much!
class NixIs {
int var;
static int global;
public:
NixIs(int val = 0)
{
global = val;
}
I think you mean "field" instead of "attribute"
Your code is valid C++ but it does not initialize the static field global, as it's an instance constructor.
If you want to initialize NixIs::global with a trivial constant value (known at compile-time) you can specify it inline in the header:
NixIs.h:
class NixIs {
static int global = 0;
}
If you have a non-constant initial value (such as a parameterless free-function result) then the static field initializer needs to be in a code-file (instead of a header). You need to specify the static field in addition to its type and the initial value of the static field:
NixIs.h:
class NixIs {
static int global;
}
NixIs.cpp:
int NixIs::global = nonTrivialValue;
If you want to initialize multiple static fields in a particular order or with function-result values you'll need to use a hack because C++ does not have static constructors. See here: Static constructor in c++
Initializing an attribute in a constructor is usually done using the initializer list. For instance, you could initialize the non-static attribute in your class like this:
NixIs( int init_val) : val(init_val) {
// do stuff
}
I think that is what you meant. Trying to initialize a static class member like this would be an error. However, all class methods including constructors and destructors can access static members. In your example, 'global' would simply be overwritten with each new instance that is created.
NixIs first(1); // first.global is now 1
NixIs second(2); // first.global is now also 2 (same as second.global)
I have a private static member variable of a class Central, with type map. I want to populate this map with " Base* " pointers, which point to instances of classes deriving from " Base ". These instances of the derived classes must be stored in dynamic memory. There is a bit of template fun involved also. I did try a method to populate the map, but it gave me a compilation error (which will be stated later).
Here is a code snippet for clarity:
#include <all_necesary_std_headers>
class Base
{
/* guts */
};
template<class CType>
class Derived: public Base
{
/* innards */
};
class Central
{
/* partial entrails */
private:
// the static map I was referring to
static std::map<string, Base*> base_map;
};
// Initializing the static map here
std::map<string, Base*> Central::base_map;
class Test1
{
/* viscera */
};
// Compilation error here, on next line of code.
Central::base_map["Test1"] = dynamic_cast<Base*>( new Derived<Test1>);
class Test2
{
/* bowels */
};
// Compilation error here, on next line of code.
Central::base_map["Test2"] = dynamic_cast<Base*>( new Derived<Test2>);
This is the Compilation error that I get:
error: expected constructor, destructor, or type conversion before '=' token;
I already have a destructor that frees the memory allocated by the map, so no need to remind me. I want to use the class " Central " in main(). This class structure will be used to dynamically create new instances of classes, from class names stored in files.
Hope it is clear, please say if anything isn't.
Assignment statements can only go in functions, not at namespace scope.
In C++11, you can initialise the map in its declaration:
std::map<string, Base*> Central::base_map = {
{"Test1", new Derived<Test1>},
{"Test2", new Derived<Test2>}
};
If you're stuck in the past, then you'll need to use a function to populate the map; perhaps something like:
std::map<string, Base*> make_base_map() {
std::map<string, Base*> map;
map["Test1"] = new Derived<Test1>;
map["Test2"] = new Derived<Test2>;
return map;
}
std::map<string, Base*> Central::base_map = make_base_map();
Also, note that you can't use dynamic_cast unless these types are polymorphic (i.e. Base has at least one virtual function). You can convert Derived<T>* to Base* without a cast, as I've done in my examples; but if you need to convert back with dynamic_cast then you'll need to make sure they are polymorphic.
UPDATE: If you want to be able to register each class separately by adding code only to that class's implementation files, then you'll need to declare a static object that registers the class in its constructor. Now we run into the initialisation order fiasco: if static objects are initialised in different translation units then the initialisation order is unspecified, so you can't safely access one from the constructor of the other.
We can fix this by making the map a local static variable, initialised the first time it's accessed:
static std::map<string, Base*> & base_map() {
static std::map<string, Base*> map;
return map;
}
Now we can define the class to register the classes:
template <typename T>
struct BaseMapEntry {
explicit BaseMapEntry(string name) {
base_map()[name] = new Derived<T>;
}
};
And use it for each class:
// header file
class Test1
{
static BaseMapEntry<Test1> entry;
/* gubbins */
};
// source file
BaseMapEntry<Test1> Test1::entry("Test1");
(Alternatively, you could make it a static namespace-scope object in the source file, rather than a static member; the choice is largely aesthetic. Unfortunately, whatever you do will have to be defined in the source file due to the One Definition Rule.)
use this line to add a new value to the map (from member-functions or ctor):
Central::base_map["Test1"] = new Derived<Test1>();
if you want to fill it with some values on initialize, use boost::assign or C++11:
std::map<string, Base*> Central::base_map = {
{"Test1", new Derived<Test1>()},
{"Test2", new Derived<Test2>()}
};
When we declare some variable inside class or struct in C/C++, we have to make an object of class or struct to allocate memory for the variable.
Why can't we just access these variables without any object?
Well, the answer is really: because that's the whole point of this language feature. The very idea of a data member of a class is for it to be an integral part of class object. It begins its life together with the entire class object and it ends its life together.
If you have two class objects, you have two completely independent sets of data members. If you have 50 class objects, you have 50 completely independent sets of data members. If you have zero class objects, you have no sets of data members to access. In other words, you cannot access these "variables" without a class object simply because they do not exist without a class object.
You are not really "declaring a variable" when you declaring a data member of a class in a class definition. Class definition simply describes the layout of class type. By itself it produces nothing physical, i.e noting that would live in data memory, noting you can physically access.
Meanwhile, C++ language has such concept as static member of the class. Static data members of the class are not associated with specific class objects. They exist independently. In fact, static data members are just ordinary global variables covered by a fairly thin layer of C++-specific "syntactic sugar" (more elaborate naming, access control etc.) Static data members of the class can be accessed as ordinary variables, without any object.
In other words, it is not a question of "why?" but rather a question of what you need. If you want non-static data member functionality, use non-static data members. If you want static data member functionality... well, you get the idea.
A class is just a 'layout' used to specify how instanced object will be constructed, destroyed and how they will behave. For an imaged comparizon with buildings: a class is the plan used to build the house. The object is the house itself.
If you want variable without objects, use global variables. You can put them in a namespace:
namespace test
{
int answer = 42; // Initialization is optional
}
// ...
void f()
{
// Use it like this:
test::answer = 0;
}
You can also use static members:
class MyClass
{
public:
static int value;
};
Usually, you declare a member variable inside a class precisely because you want it to be part of an object of that class type. That's what that language feature is for: to allow you to have many distinct objects, each with its own state independent of any other object.
In C++ (but not C), you can declare it static if you want a single variable, independent of any object. This will have static storage duration, just like a variable declared outside a class. In C, global variables are the only option if you want something like this.
For example:
struct thing {
int a; // part of a "thing" object
static int b; // not part of a "thing"
};
// Static variables need a definition, in exactly one source file
int thing::b;
int main() {
thing::b = 1; // OK: no object needed
thing::a = 2; // ERROR: object needed
thing t1;
t1.a = 3; // OK: accessing object member
t1.b = 4; // OK: equivalent to "thing::b"
thing t2;
t2.a = 5; // OK: accessing object member
t2.b = 6; // OK: equivalent to "thing::b"
std::cout << t1.a; // prints 3
std::cout << t2.a; // prints 5 - independent of t1.a
std::cout << t1.b; // prints 6
std::cout << t2.b; // prints 6 - same variable as t1.b (aka thing::b)
}
Using the static keyword:
class A {
public:
static int varaible;
};
int A::variable = 5;
Then you can access the variable without an object anytime. As follows.
A::varaible = 25;
Things you'll need to know:
You will need to use the scope operator(::) to access a static member.
Definition of a static member must be done outside of the class. The above statement int A::variable = 5; is an definition of a static member.
All objects of type A (included inherited objects) share a static member. [1]
[1]
A a;
A b;
a::variable == b::variable == 25;
//if we change a::variable
a::variable = 26;
//b::variable has the same value.
b::variable == a::variable == 26;
This question already has answers here:
When do I use a dot, arrow, or double colon to refer to members of a class in C++?
(4 answers)
Closed 4 months ago.
I created a class called Kwadrat. The class has three int fields. My Development Environment suggests that I access the fields from Kwadrat created objects via the :: & -> operators. I tried both operators, and found that the -> operator is able to successfully access the data in the objects fields, although, the same cannot be said for the -> operator.
I have also found that the . operator will access class members as well. I am confused, and don't understand why there are three members for accessing object members &/or methods. Can someone please explain to me what the difference is between the three operators?
1. ->
2. ::
3. .
#include <iostream>
using namespace std;
class Kwadrat{
public:
int val1,
val2,
val3;
Kwadrat(int val1, int val2, int val3)
{
this->val1 = val1; // Working
this.val2 = val2; // Doesn't Work!
this::val3 = val3; // Doesn't Work!
}
};
int main()
{
Kwadrat* kwadrat = new Kwadrat(1,2,3);
cout<<kwadrat->val1<<endl;
cout<<kwadrat->val2<<endl;
cout<<kwadrat->val3<<endl;
return 0;
}
1.-> for accessing object member variables and methods via pointer to object
Foo *foo = new Foo();
foo->member_var = 10;
foo->member_func();
2.. for accessing object member variables and methods via object instance
Foo foo;
foo.member_var = 10;
foo.member_func();
3.:: for accessing static variables and methods of a class/struct or namespace. It can also be used to access variables and functions from another scope (actually class, struct, namespace are scopes in that case)
int some_val = Foo::static_var;
Foo::static_method();
int max_int = std::numeric_limits<int>::max();
In C++ you can access fields or methods, using different operators, depending on it's type:
ClassName::FieldName : class public static field and methods
ClassInstance.FieldName : accessing a public field (or method) through class reference
ClassPointer->FieldName : accessing a public field (or method) dereferencing a class pointer
Note that :: should be used with a class name rather than a class instance, since static fields or methods are common to all instances of a class.
class AClass{
public:
static int static_field;
int instance_field;
static void static_method();
void method();
};
then you access this way:
AClass instance;
AClass *pointer = new AClass();
instance.instance_field; //access instance_field through a reference to AClass
instance.method();
pointer->instance_field; //access instance_field through a pointer to AClass
pointer->method();
AClass::static_field;
AClass::static_method();
Put very simple :: is the scoping operator, . is the access operator (I forget what the actual name is?), and -> is the dereference arrow.
:: - Scopes a function. That is, it lets the compiler know what class the function lives in and, thus, how to call it. If you are using this operator to call a function, the function is a static function.
. - This allows access to a member function on an already created object. For instance, Foo x; x.bar() calls the method bar() on instantiated object x which has type Foo. You can also use this to access public class variables.
-> - Essentially the same thing as . except this works on pointer types. In essence it dereferences the pointer, than calls .. Using this is equivalent to (*ptr).method()
You have a pointer to an object. Therefore, you need to access a field of an object that's pointed to by the pointer. To dereference the pointer you use *, and to access a field, you use ., so you can use:
cout << (*kwadrat).val1;
Note that the parentheses are necessary. This operation is common enough that long ago (when C was young) they decided to create a "shorthand" method of doing it:
cout << kwadrat->val1;
These are defined to be identical. As you can see, the -> basically just combines a * and a . into a single operation. If you were dealing directly with an object or a reference to an object, you'd be able to use the . without dereferencing a pointer first:
Kwadrat kwadrat2(2,3,4);
cout << kwadrat2.val1;
The :: is the scope resolution operator. It is used when you only need to qualify the name, but you're not dealing with an individual object at all. This would be primarily to access a static data member:
struct something {
static int x; // this only declares `something::x`. Often found in a header
};
int something::x; // this defines `something::x`. Usually in .cpp/.cc/.C file.
In this case, since x is static, it's not associated with any particular instance of something. In fact, it will exist even if no instance of that type of object has been created. In this case, we can access it with the scope resolution operator:
something::x = 10;
std::cout << something::x;
Note, however, that it's also permitted to access a static member as if it was a member of a particular object:
something s;
s.x = 1;
At least if memory serves, early in the history of C++ this wasn't allowed, but the meaning is unambiguous, so they decided to allow it.
The three operators have related but different meanings, despite the misleading note from the IDE.
The :: operator is known as the scope resolution operator, and it is used to get from a namespace or class to one of its members.
The . and -> operators are for accessing an object instance's members, and only comes into play after creating an object instance. You use . if you have an actual object (or a reference to the object, declared with & in the declared type), and you use -> if you have a pointer to an object (declared with * in the declared type).
The this object is always a pointer to the current instance, hence why the -> operator is the only one that works.
Examples:
// In a header file
namespace Namespace {
class Class {
private:
int x;
public:
Class() : x(4) {}
void incrementX();
};
}
// In an implementation file
namespace Namespace {
void Class::incrementX() { // Using scope resolution to get to the class member when we aren't using an instance
++(this->x); // this is a pointer, so using ->. Equivalent to ++((*this).x)
}
}
// In a separate file lies your main method
int main() {
Namespace::Class myInstance; // instantiates an instance. Note the scope resolution
Namespace::Class *myPointer = new Namespace::Class;
myInstance.incrementX(); // Calling a function on an object instance.
myPointer->incrementX(); // Calling a function on an object pointer.
(*myPointer).incrementX(); // Calling a function on an object pointer by dereferencing first
return 0;
}
-> is for pointers to a class instance
. is for class instances
:: is for classnames - for example when using a static member
The '::' is for static members.
Others have answered the different syntaxes, but please note, when you are doing your couts, you are only using ->:
int main()
{
Kwadrat* kwadrat = new Kwadrat(1,2,3);
cout<<kwadrat->val1<<endl;
cout<<kwadrat->val2<<endl;
cout<<kwadrat->val3<<endl;
return 0;
}