I have this C++ class:
class Test
{
private:
string _string;
public:
Test()
{
}
Test(const char *s)
{
Test((string)s);
}
Test(string s)
{
_string = s;
}
operator const char *()
{
return _string.c_str();
}
operator string()
{
return _string;
}
};
If I use this code in main "1234" is printed to the console:
int main()
{
Test test = string("1234");
string s = test;
cout << s << endl;
return 0;
}
But with this, nothing is printed:
int main()
{
Test test = "1234"; // Only change
string s = test;
cout << s << endl;
return 0;
}
The only difference is which constructor is called. It apperas that the _string variable is a default string instance with the value "" but I don't see how that could have happend. I thought that since _string is on the stack, the assignment I do is safe.
This
Test(const char *s)
{
Test((string)s);
}
does not chain the constructors. It just creates a temporary object in the body of the function. What you need is:
Test(const char *s) : Test(string(s))
{
}
Related
I'm using the following example from Stroustrup C++ 4th Ed. Page 218. My question is regarding the destructor.
Questions:
How does placement new(&s) string{ss} allocate room for the new string when it's my understanding that union size is fixed to the largest member? Is string s not a 0 element string? If so, how does the placement new create a larger string if there is not enough space in the union?
#include <iostream>
#include <string>
using namespace std;
class Entry2 { // two alternative representations represented as a union
private:
enum class Tag { number, text };
Tag type; // discriminant
union { // representation
int i;
string s; // string has default constructor, copy operations, and destructor
};
public:
struct Bad_entry { }; // used for exceptions
string name;
Entry2(int n) : type{Tag::number}, i{n} { };
Entry2(string ss) : type{Tag::number} { new(&s) string{ss}; };
~Entry2();
Entry2& operator=(const Entry2&); Entry2(const Entry2&);
// ...
int number() const; string text() const;
void set_number(int n);
void set_text(const string&); // ...
};
Entry2::~Entry2()
{
if (type==Tag::text)
s.~string();
}
int Entry2::number() const
{
if (type!=Tag::number) throw Bad_entry{};
return i;
}
string Entry2::text() const
{
if (type!=Tag::text) throw Bad_entry{};
return s;
}
void Entry2::set_number(int n)
{
if (type==Tag::text) {
s.~string();
type = Tag::number;
}
i = n;
}
void Entry2::set_text(const string& ss)
{
if (type==Tag::text)
s = ss;
else {
new(&s) string{ss};
type = Tag::text;
}
}
Entry2& Entry2::operator=(const Entry2& e)
{
if (type==Tag::text && e.type==Tag::text) {
s = e.s; // usual string assignment
return *this;
}
if (type==Tag::text)
s.~string(); // explicit destroy (ยง11.2.4)
switch (e.type) {
case Tag::number:
i = e.i;
break;
case Tag::text:
new(&s) string{e.s};
type = e.type;
}
return *this;
}
int main(int argc, char *argv[])
{
Entry2 e0(0);
cout << e0.number() << endl;
try {
e0.text();
} catch (...) {
cout << "caught except" << endl;
}
e0.set_text("abcd");
cout << e0.text() << endl;
return 0;
}
No, the destructor should not always do this. Remember that in a union, only one of the fields is actually active at any one time. If the std::string member of the union isn't active, then calling its destructor would be a Bad Thing (cause undefined behavior) because there wasn't a string there to destroy. Instead, we instead only call the destructor on that std::string member if at some previous point in time we activated the std::string there.
Hope this helps!
I'm working on a project for class, but keep getting the error: no instance of overloaded function matches argument list. It is referencing my String classes. What I am trying to do is create a Copy, Concat and Count functions with out using the string class. Any help would be greatly appreciated.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
class String
{
private:
char str[100];
char cpy[100];
public:
static const char NULLCHAR = '\0';
String()
{
str[0] = NULLCHAR;
cpy[0] = NULLCHAR;
}
String(char* orig, char* cpy)
{
Copy(orig, cpy);
}
void Display()
{
cout << str << endl;
}
void Copy(char* orig, char* dest)
{
while (*orig != '\0') {
*dest++ = *orig++;
}
*dest = '\0';
}
void Copy(String& orig, String& dest)
{
Copy(orig.str, dest.cpy);
}
void Concat(char* orig, char* cpy)
{
while (*orig)
orig++;
while (*cpy)
{
*orig = *cpy;
cpy++;
orig++;
}
*orig = '\0';
}
void Concat(String& orig, String& cpy)
{
Concat(orig.str, cpy.cpy);
}
int Length(char* orig)
{
int c = 0;
while (*orig != '\0')
{
c++;
*orig++;
}
printf("Length of string is=%d\n", c);
return(c);
}
};
int main()
{
String s;
s.Copy("Hello");
s.Display();
s.Concat(" there");
s.Display();
String s1 = "Howdy";
String s2 = " there";
String s3;
String s4("This String built by constructor");
s3.Copy(s1);
s3.Display();
s3.Concat(s2);
s3.Display();
s4.Display();
system("pause");
return 0;
}
It looks like your Copy and Concat functions each take two parameters, yet you pass them both a single parameter. If you want to copy them into a String object, your code should look more like:
String Copy(char* orig)
{
// Same copy logic you have,
// except copy into "*this"
}
As the error message says, There is no version of the constructor for your String class that takes a single parameter. You have a default constructor and one that takes two parameters.
You need to define one which takes a single parameter and initializes the str
String s4("This String built by constructor");
this statement needs construction function
String(char *);
I have class Pstring
class Pstring
{
private:
string palindrome;
public:
Pstring() { palindrome = ""; }
Pstring(string pal) { setString(pal); }
void setString(string pal) { palindrome = pal; }
string getPal() const { return palindrome; }
};
an object in my main method Pstring palindrome(palin) defined by
string palin = "";
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
and a current test method bool isPalindrome(string pal)defined as
bool isPalindrome(string pal)
{
bool flag;
cout << "Do I have access to this?";
cout << pal;
//code goes here to check for palindrome, return bool
}
I want to have my Pstring class object palindrome use the method isPalindrome in main, but when I try and invoke the method by using palindrome.isPalinedrome(palin); it doesn't seem to have access to the method.
What can I do to allow a method outside the class to be used by a class object in main?
You don't have a isPalinedrome() method defined in the Pstring class, so you can't call it as palindrome.isPalinedrome() in your main code.
Instead of having Pstring try to call a function in your main code, you should move the palindrome logic into Pstring, and then the main code can ask Pstring when needed.
Try this:
class Pstring
{
private:
string value;
public:
Pstring() { }
Pstring(const string &s) { setString(s); }
void setString(const string &s) { value = s; }
string getString() const { return value; }
// add this...
bool isPalindrome() const {
//code goes here to check value for palindrome, return bool
}
};
Then your main code can do this:
bool isPalindrome(const string &value)
{
Pstring palindrome(value);
return palindrome.isPalindrome();
// or simply:
// return Pstring(value).isPalindrome();
}
int main()
{
string palin;
cout << "Enter a palindrome:\n";
getline(cin, palin);
if (isPalindrome(palin)) {
// do something ...
} else {
// do something else...
}
return 0;
}
Or this:
int main()
{
string palin;
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
if (palindrome.isPalindrome()) {
// do something ...
} else {
// do something else...
}
return 0;
}
You should add your test method into the class:
class Pstring
{
private:
string palindrome;
public:
// you don't need to initialize palindrome = "" (it's initialized by default)
Pstring() {}
// always pass strings as const reference unless you have
// special reason to do it another way...
Pstring(const string& pal) { setString(pal); }
void setString(const string& pal) { palindrome = pal; }
string getPal() const { return palindrome; }
bool isPalindrome() const // you don't have to pass string
{
bool flag;
cout << "Do I have access to this?";
cout << palindrome; // please note this
//code goes here to check for palindrome, return bool
}
};
And also please note the typo:
palindrome.isPalinedrome(palin);
You can use function pointer to implement it:
declare class:
class Pstring{
private:
string palindrome;
public:
Pstring() { palindrome = ""; }
Pstring(string pal) { setString(pal); }
void setString(string pal) { palindrome = pal; }
string getPal() const { return palindrome; }
//add a function pointer member:
bool(*isPalindrome) (string);
};
then define function:
bool isPalindrome(string pal)
{
bool flag;
cout << "Do I have access to this?";
cout << pal;
//code goes here to check for palindrome, return bool
return true;
}
now you can write code in main function:
string palin = "";
cout << "Enter a palindrome:\n";
getline(cin, palin);
Pstring palindrome(palin);
palindrome.isPalindrome = isPalindrome;//bind function
you can use the function by the object now:
palindrome.isPalindrome(palin);
Sorry. what's the point to create this class? the only thing you need is the helper function isPalindrome(const std::string&). If you need some kinda scope protection, put it into a namespace may look better
Sorry but I have to say you are just make things complicated.
C++ is not java. If you don't use it, you should not pay for it.
I'm coding a simple c++ factory and I get an error that I don't understand.
This is my class definition:
MSGFactory.hpp
class MSGFactory
{
public:
static MSGFactory * getInstance();
void registerMSG(const std::string MSGType , createMSGFn constructor );
MSGData *createMessage(const std::string &MSGType);
private:
static MSGFactory * inst;
std::map<std::string,createMSGFn> MSGPool;
};
and this is its implementation:
MSGFactory.cpp
MSGFactory * MSGFactory::getInstance()
{
if(inst == NULL) inst = new MSGFactory();
return inst;
}
void MSGFactory::registerMSG(const std::string MSGType , createMSGFn constructor )
{
MSGPool.insert(factoryBucket(MSGType,constructor));
}
MSGData * MSGFactory::createMessage(const std::string &MSGType)
{
std::map<std::string,createMSGFn>::iterator it;
it = MSGPool.find(MSGType);
if( it != MSGPool.end() )
return it->second();
return NULL;
}
I wrote this test program:
T_MSGFactory.cpp
class MSGOne : MSGData
{
public:
MSGOne(){}
~MSGOne() {{std::cout<<"Derived destructor called\n";}}
std::string type() { std::cout << "Type One" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGOne(); }
};
class MSGTwo : MSGData
{
public:
MSGTwo(){}
~MSGTwo() {std::cout<<"Derived destructor called\n";}
std::string type() { std::cout << "Type Two" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGTwo(); }
};
class MSGThree : MSGData
{
public:
MSGThree(){}
~MSGThree() {std::cout<<"Derived destructor called\n";}
std::string type() { std::cout << "Type Three" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGThree(); }
};
int main(int argc, char **argv)
{
std::cout << "PROVA" << std::endl;
MSGFactory::getInstance()->registerMSG("ONE", &MSGOne::Create );
MSGFactory::getInstance()->registerMSG("TWO", &MSGTwo::Create );
MSGFactory::getInstance()->registerMSG("THREE", &MSGThree::Create );
return 0;
}
but compiling it with "g++ T_MSGFactory.cpp MSGFactory.cpp" I get this error:
1) "riferimento non definito a" is "undefined reference to"
2) "nella funzione" is "in function"
Can someone help me? Thanks
In the top of your MSGFactory.cpp file, just after the includes, in the global scope, you should declare the static member.
like this:
MSGFactory* MSGFactory::inst=NULL;
Static member variables must be defined, usually in the source file.
Add this to your MSGFactory.cpp
MSGFactory* MSGFactory::inst = 0;
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
How can we initialize a string argument in the C++ function prototype? I want to assign a default value for a string argument in my function
int test(string& s="rom");
int test(string& s) {
return s.size();
}
int main(int argc, char *argv[]) {
cout << test() << endl;
return 0;
}
You can use this:
void func(const std::string& argument = "default") { ... }
you can also do:
void func(std::string argument = "default") { ... }
but that really depends on if you need that copy inside the function.
Like this:
void func(int a, string str="default-string")
{
cout << a << str << endl;
}
And call like this:
int main(void)
{
func(3); // use default string
func(3, "new-string"); // use new string
return 0;
}