In C++ is it possible to declare a class which has a private std::string data member which is initialized with the stringized / stringified name of the instance symbol name? I can see that this couldn't work for temporaries, but for lvalues is it possible?
Here is what I would like:
#include <iostream>
#include <string>
class symbol {
public:
symbol() { // here goes some magical sauce }
void print() { std::cout << s_ << std::endl; }
private:
std::string s_;
};
int main() {
symbol bar, bah;
bar.print() // should print "bar" to STDOUT
bah.print() // should print "bah" to STDOUT
}
If I were to change the constructor to accept a string and introduce a preprocessor macro, then I can almost get what I want, but it smells bad.
#define makesymbol(x) foo x(#x)
symbol(const std::string & s) : s_(s) {}
// Now I can do:
makesymbol(test);
test.print(); // <--- This prints "test" followed by a newline to STDOUT
Basically what I would like to avoid is for the user to have to declare instances of symbols like:
symbol phi("phi");
Because it is annoying to read, annoying to type, and redundant. I can see why in some cases you might want a different string stored than the variable name, but I'm specifically trying to the solve the problem where you know you want the string to be equal to the stringized variable name.
Related
So I'm an newbie to programming and I have encountered a
case for which I suppose qualifies as an authentic question
in this awesome forum. Is there a way to write statements inside my get functions so that I can obtain all the changed data member values without having to create multiple get functions
for each data member?
Regards
I am practicing building programs which are easy to maintain by localizing the effects to a class's data members by accessing and manipulating the data members through their get and set functions. In this regard I have two data members for which I wish to change. After compiling, the set functions works well by changing the values but the get functions can only return one of the data member values at a time.
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
string getCourseName()
{
return CourseCode;
return CourseName;
}
void displayMessage()
{
cout<<"Welcome to the GradeBook for: \n" <<getCourseName()
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
After compiling and running the program, the program outputs the CourseCode but the CourseName doesn't get displayed. I had to create two get functions each to obtain the two data members. I don't want to have 2 get functions to obtain the data member values. I just want to use one get function to keep the code at minimum.I wish to use one get function to return two values for each data member. I have already tried using one return statement and separated the data members with a comma.
Your idea of using return twice cannot work, the first return will return control to the caller and the second will never be executed. You should have got warning about it from your compiler.
I believe that an initial solution could be to use std::pair (docs: https://en.cppreference.com/w/cpp/utility/pair), see snippet below.
NOTE: using namespace std; (which is most likely what you are doing in the code you do not show), is a bad practice, consider using the fully qualified name
#include <string>
#include <utility>
#include <iostream>
//Bad practice, I added it only to keep differences with OP code small
using namespace std;
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
std::pair<string, string> getCourseName()
{
return {CourseCode, CourseName};
}
void displayMessage()
{
//only in C++17
auto [code, name] = getCourseName();
cout<<"Welcome to the GradeBook for: \n" << code << " - " << name
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
Note that auto [code, name] is a feature called structured binding, available only in C++17, if you have an older compiler, you have to return a std::pair<std::string, std::string> and access its elements using the member variables first and second.
Now, std::pair is good for this contrived example, but, for your case, you might want to consider doing something a bit more readable, because the elements of the pair have the same type so the user of your library will have difficulties remembering what is the first and second element. So you might want to use a custom-made struct with some more meaningful names.
#include <string>
#include <utility>
#include <iostream>
//Bad practice, I added it only to keep differences with OP code small
using namespace std;
struct CourseCodeAndName{
std::string code;
std::string name;
};
class GradeBook
{
public:
void setCourseName(string code,string name)
{
CourseCode = code;
CourseName = name;
}
CourseCodeAndName getCourseName()
{
return {CourseCode, CourseName};
}
void displayMessage()
{
auto codeAndName = getCourseName();
cout<<"Welcome to the GradeBook for: \n" << codeAndName.code << " - " << codeAndName.name
<<endl;
}
private:
string CourseName;
string CourseCode;
};//end class GradeBook
See this example. Alternatively you can use std::tuple.
class GradeBook
{
/* ... */
public:
std::pair<std::string, std::string> get(){
return std::make_pair(CourseName, CourseCode);
}
};
int main()
{
GradeBook book1("Hello","World")
auto result = book1.get();
cout << result.first << result.second;
}
If you write:
return x,y;
or:
return x;
return y;
You should know that in first case you get the last value (you get y), and in second case you get the value of first return (you get x, because as soon as compiler see return, function will return the value, and then function will go in epilogue state (cleaning of stack memory assigned to function, both inline and non-inline function).
And about the use of get function it's normal. If you want to use the value to do something of logic (not to display), yes you should use a lot of get function. Instead if you want to display the values, use a void function, for example "void printData();", and inside it write code to print data. You probably setted the class variables as private (following the encapsulation rules) so you will have access to them inside the print function.
I am looking for a way to print the name of the variable on which an instance's constructor is being invoked, from inside the constructor:
#include <iostream>
struct A {
A() {
std::cout << "variable name = " /*magic here*/ << "\n";
}
};
int main() {
A abc; // should output "variable name = abc"
A def; // should output "variable name = def"
}
Is this possible and how?
I don't think there's any way to do that without using macros.
If your class had a constructor taking a const char* then you could use a fake constructor macro to pass the variable name into the real constructor. I'm not sure why you'd want to do that though and this is a pretty ugly solution.
#define CONSTRUCT(type, name) type name(#name)
For e.g. I define a C++ class like this:
class cat : public animal
{
public:
cat(const char* nameString) : m_name(nameString) {}
~cat(){}
const char* getName() {return m_name.c_str();}
private:
std::string m_name;
};
Later:
cat kitty("Garfield");
printf("%s", kitty.getName());
For the example code above, ctags could tell me the inheritance, members, methods, access type (public, private) etc.
But how can I find out that kitty is an instance of cat?
std::cout << "kitty is a: " << typeid(kitty).name() << '\n';
but, as you can see, could be not exactly what you want.
Returns an implementation defined null-terminated character string
containing the name of the type. No guarantees are given, in
particular, the returned string can be identical for several types and
change between invocations of the same program.
You can compare the typeid with other know types, like cat.
And you can make it in the same direction/style you have with the object names, and include a virtual function in Animal :
virtual string whatAnimal()const{return "animal";}
and in derived classes:
string whatAnimal()const override {return "cat";}
Now you have complete control over the string you what for each type, not related to the name convention you use in your code.
It is possible to get the class name of an object with typeid. However, compiler will magle the name, so you should demangle it appropriately at runtime.
An example:
#include <iostream>
#include <cxxabi.h>
class cls {};
void main(){
cls obj;
int status;
char * demangled_name = abi::__cxa_demangle(typeid(obj).name(),0,0,&status);
std::cout << demangled_name << std::endl;
free(demangled_name);
return;
}
will output:
cls
Directly answering your question of how to check if kitty is an instance of cat can be done this way:
if(typeid(cat) == typeid(kitty))
// do something if kitty is a cat
Note, typeid(YourClass).name() returns nYourClass, where n is the length of the class name.
I'm trying to initialize a private variable of my Class passing a const string &aString to it as parameter.
Here's my method:
void Image::initWithTextureFile(const std::string &inTextureName)
{
Texture2D *imTexture = TEXTURE_MANAGER->createTexture(inTextureName);
if(imTexture)
{
texture = imTexture;
scale = 1.0f;
name = inTextureName; //name is a private string variable inside my class
initImplementation();
}else {
printf("Could not load texture when creating Image from file %s\n",inTextureName.c_str());
}
}
My problem is the following, when I call this method I do it like:
myInitializer.initWithTextureFile("myFile.bmp");
When I'm inside the scope of initWithTextureFile the name variable takes the value of inTextureName. For this example if I cout << name << endl; inside initWithTextureFile i would get "myFile.bmp"
But when I leave the scope of the function, name looses it's value, so when i cout << name << endl; I get nothing printed in the console.
Could anyone point me out to what's going on here?
Name is declared:
private:
std::string name;
If you're outside the class scope, and cout << name compiles at all, it means you have another variable named name, and that's what's being picked up. If you want to refer to it outside the class, you'll have to come up with a way that will export it. You might, for example, have a member function like const std::string &GetName() { return name; }.
You either omitting something in your description or are not showing appropriate code that could help solve your problem.
This works:
#include <iostream>
#include <string>
using namespace std;
struct A
{
void f(const string& str) { name = str; }
void g() { cout << name << endl; }
string name;
};
int main()
{
A a;
a.f("test");
a.g();
}
Output:
test
That should work. Are you sure it is not being modified somewhere else, such as in initImplementation?
The problem probably have to do with the name variable : is it a pointer or ref to string instead of a plain string ?
The only reasonable explanation here is that you must be working with two different name objects. The one you declared as a class member should hold its value when you exit the method. It is just that outside the class method you must be printing a completely different name, which is empty.
I was going to say something about short-lived stack objects but I realised that was wrong. What it could be is something to do with exporting the containing class from a DLL.
If so, you might find a warning like this:
c:\yourclass.h(7): warning C4251: 'YourClass::name_' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'YourClass'
This thread describes more.
How is 'name' declared? It seems like maybe it's declared as a reference instead of an object.
Try:
name = std::string(inTextureName);
I am very new to C++ and still trying to learn syntax and best practices.
I've defined a method with a single parameter:
void foo(const std::string& name)
1) Is this a proper parameter declaration for a function that will be taking in a string defined by the user in, for example, a main method?
2) If this is proper/recommended syntax, what would an instantiation of a sample parameter look like?
Yes, that is the correct syntax. You can call it and provide parameters several different ways:
With a string literal:
foo("bar");
With a string variable:
std::string b = "bar";
foo(b);
With the result of a function return type string:
std::string quux();
foo(quux());
With a char* variable:
int main(int argc, char const* argv[]) {
foo(argv[0]);
}
I'm not sure if I fully understand your question, but I'll try to clarify it.
You use the terminology 'method'. I'm assuming that your method is encapsulated in a class? If so, then :-
In your header file (eg. source.h),
class dog
{
...
public:
void foo(const std::string &name);
...
};
In your source file (eg. source.cpp)
void dog::foo(const std::string &name)
{
// Do something with 'name' in here
std::string temp = name + " is OK!";
}
In your 'main' function, you can instantiate your 'dog' class, and call the 'foo' function like :-
void blah()
{
dog my_class;
my_class.foo("Testing my class");
}
If you want a function (ie. a 'method' that is not encapsulated within a class), then what you have is correct.
In your source file (eg. source.cpp)
void foo(const std::string &name)
{
// Do something with 'name' in here
std::string temp = name + " is OK!";
}
If you want to be able to call your function from outside that particular source file, you'll also need to forward declare your function in a header file.
In your header file (eg. source.h)
void foo(const std::string &name);
To call your function,
void blah()
{
foo("Testing my class");
}
Hope this helps!
1)
It is a proper parameter declaration if function foo() doesn't mean to change the string. The 'const' keyword is used to signify that the string won't be changed by the receiver.
If you write code in foo() which modifies the string you will get compiler error/warning.
2)
std::string theString = "Hello";
foo( theString );
Is this a proper parameter declaration for a function that will be taking in a string defined by the user in, for example, a main method?
Yes.
#include <string>
using namespace std;
void foo(const string& name)
1) Yes, that's a very good way to do it if you only need to read the string in the function.
2) There is no instantiation going on?
1) For most functions, it would be a fine signature. However, since you mentioned main(), there are only two valid signatures:
int main()
int main(int argc, const char* argv[])
...as you can see, you have to use C-style strings due to C-legacy compatibility (and efficiency)
2) Not sure I understand your second question, but since std::string has a constructor that takes a const char*, you can just say:
foo("hello");
or:
std::string input;
std::cout << "Enter some text: ";
std::cin >> input;
foo(input);