...

View Full Version : C++ redefinition of class



brad211987
09-08-2009, 03:19 AM
Brushing up on C++ for a class and started in a new text book with some of the basic exercises. This particular one is to implement a Custom String class using primitive strings. I've created a class named MyString, a header file for it, and a test file that uses it. My problem is that when I compile, i get an error saying


MyString.cpp:3: error: redefinition of ‘class MyString’
MyString.h:5: error: previous definition of ‘class MyString’


I have included the header guards in my header file to prevent this, but I've obviously missed a beat somewhere as it is not working for me. Any ideas on what I've missed here? I've looked at examples of defining header files for classes and using header guards, but haven't been able to find out what I am missing yet.

Here is the code I'm working with so far, none of the member functions are implemented as I am just trying to get to a project that compiles to start with.

MyString.h


#ifndef MYSTRING_H
#define MYSTRING_H

class MyString
{
private:
char * storedValue;
public:
MyString();
MyString(const MyString&);
MyString(char * str);
int length();
void resize(int n, char c);
void clear();
bool empty();
void insert(int pos1, const MyString& str);
void insert(int pos1, const char* s);
void erase(int pos, int n);
int find(const MyString& str);
int find(const char* s);
int compare( const MyString& str);
int compare(const char* s);
char* getStr();
};
#endif


MyString.cpp


#include "MyString.h"

class MyString
{
private:
char * storedValue ;

public:
~MyString()
{
delete storedValue;
}//end destructor

const MyString & operator=(const MyString & str)
{
if (this != &str)
storedValue = str.storedValue;

return *this;
}//end operator method

MyString(const MyString & str) : storedValue(str.storedValue)
{
}//end copy constructor

MyString(char * str)
{
storedValue = str;
}//end constructor MyString

MyString()
{
storedValue = '\0';
}//end constructor MyString

int length()
{

}//end member function length

void resize(int n, char c)
{

}//end member function resize

void clear()
{

}//end member function clear

bool empty()
{
return true;
}//end member function empty

void insert(int pos1, const MyString& str)
{

}//end member function insert

void insert(int pos1, const char* s)
{

}//end member function insert

void erase(int pos, int n)
{

}//end member function erase

int find(const MyString& str)
{
return 1;
}//end member function find

int find(const char* s)
{
return 1;
}//end member function find

int compare( const MyString& str)
{
return 1;
}//end member function compare

int compare(const char* s)
{
return 1;
}//end member function compare

char* getStr()
{
return storedValue;
}//end member function getStr
};//end class MyString


test.cpp


#include <iostream>
#include "MyString.h"
using namespace std;

int main(void)
{
MyString i="This is my string";
cout << "The value of i: \'" << i.getStr() << "\' and the length is: " << i.length() <<endl;
return 0;
}

oracleguy
09-08-2009, 04:25 AM
The problem is in your cpp, you are declaring another class. Member functions aren't defined that way.

As an example of how you would do it:


const MyString & MyString::operator=(const MyString & str)
{
if (this != &str)
storedValue = str.storedValue;

return *this;
}//end operator method


You don't need the class declaration or any access specifiers.

brad211987
09-08-2009, 01:07 PM
Ok, if I understand correctly.......Since I've declared the class and access specifiers in my header file, I will not need them at all in my CPP file, but instead should prefix my member function names with MyString:: to specify that they are part of the class defined in the header file? If I have it right, that makes sense. Will give it a try after work today then.

oracleguy
09-08-2009, 04:06 PM
Ok, if I understand correctly.......Since I've declared the class and access specifiers in my header file, I will not need them at all in my CPP file, but instead should prefix my member function names with MyString:: to specify that they are part of the class defined in the header file? If I have it right, that makes sense. Will give it a try after work today then.
Yes, that is correct.

brad211987
09-08-2009, 11:55 PM
Thanks! I have it working now. Taking a little bit of effort to adjust to c++ after 5 years of mostly java.

brad211987
09-09-2009, 02:42 PM
I'm back with a new issue. I am getting some sort of a memory error, that I believe is something I am doing wrong when creating my string pointer.

Here is the error:


*** glibc detected *** ./test2: munmap_chunk(): invalid pointer: 0x0000000000400acd ***
======= Backtrace: =========
/lib/libc.so.6[0x7fc89610acb8]
./test2[0x400944]
./test2[0x4009d7]
/lib/libc.so.6(__libc_start_main+0xe6)[0x7fc8960b15a6]
./test2[0x4006a9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 07:00 408868 /home/brad/project1/test2
00601000-00602000 r--p 00001000 07:00 408868 /home/brad/project1/test2
00602000-00603000 rw-p 00002000 07:00 408868 /home/brad/project1/test2
01d65000-01d86000 rw-p 01d65000 00:00 0 [heap]
7fc896093000-7fc8961fb000 r-xp 00000000 07:00 809463 /lib/libc-2.9.so
7fc8961fb000-7fc8963fb000 ---p 00168000 07:00 809463 /lib/libc-2.9.so
7fc8963fb000-7fc8963ff000 r--p 00168000 07:00 809463 /lib/libc-2.9.so
7fc8963ff000-7fc896400000 rw-p 0016c000 07:00 809463 /lib/libc-2.9.so
7fc896400000-7fc896405000 rw-p 7fc896400000 00:00 0
7fc896405000-7fc89641b000 r-xp 00000000 07:00 809485 /lib/libgcc_s.so.1
7fc89641b000-7fc89661b000 ---p 00016000 07:00 809485 /lib/libgcc_s.so.1
7fc89661b000-7fc89661c000 r--p 00016000 07:00 809485 /lib/libgcc_s.so.1
7fc89661c000-7fc89661d000 rw-p 00017000 07:00 809485 /lib/libgcc_s.so.1
7fc89661d000-7fc8966a1000 r-xp 00000000 07:00 809496 /lib/libm-2.9.so
7fc8966a1000-7fc8968a0000 ---p 00084000 07:00 809496 /lib/libm-2.9.so
7fc8968a0000-7fc8968a1000 r--p 00083000 07:00 809496 /lib/libm-2.9.so
7fc8968a1000-7fc8968a2000 rw-p 00084000 07:00 809496 /lib/libm-2.9.so
7fc8968a2000-7fc896993000 r-xp 00000000 07:00 494091 /usr/lib/libstdc++.so.6.0.10
7fc896993000-7fc896b93000 ---p 000f1000 07:00 494091 /usr/lib/libstdc++.so.6.0.10
7fc896b93000-7fc896b9a000 r--p 000f1000 07:00 494091 /usr/lib/libstdc++.so.6.0.10
7fc896b9a000-7fc896b9c000 rw-p 000f8000 07:00 494091 /usr/lib/libstdc++.so.6.0.10
7fc896b9c000-7fc896baf000 rw-p 7fc896b9c000 00:00 0
7fc896baf000-7fc896bcf000 r-xp 00000000 07:00 809443 /lib/ld-2.9.so
7fc896dae000-7fc896db1000 rw-p 7fc896dae000 00:00 0
7fc896dcb000-7fc896dce000 rw-p 7fc896dcb000 00:00 0
7fc896dce000-7fc896dcf000 r--p 0001f000 07:00 809443 /lib/ld-2.9.so
7fc896dcf000-7fc896dd0000 rw-p 00020000 07:00 809443 /lib/ld-2.9.so
7fff9edba000-7fff9edcf000 rw-p 7ffffffea000 00:00 0 [stack]
7fff9edfe000-7fff9edff000 r-xp 7fff9edfe000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted




Here is the CPP class, snipped out all but the constructors:


#include "MyString.h"
#include <string.h>
char * storedValue ;

MyString::~MyString()
{
delete storedValue;
}//end destructor

const MyString & MyString::operator=(const MyStri09ng & str)
{
if (this != &str)
storedValue = str.storedValue;

return *this;
}//end operator method

MyString::MyString(const MyString & str) : storedValue(str.storedValue)
{
}//end copy constructor

MyString::MyString(char * str)
{
storedValue = str;
}//end constructor MyString

MyString::MyString()
{
storedValue = "";
}//end constructor MyString
}


And here is my snippet of test code that does nothing but create the string for now:


#include <iostream>
#include "MyString.h"
using namespace std;

int main(void)
{
MyString i="This is my string";
//cout << "The value of i: \'" << i.getStr() << "\' and the length is: " << i.length() <<endl;

//i.clear();

///cout << "length is now: " << i.length() << endl;
//cout << "empty? " << i.empty() << endl;

return 0;
}


I commented out the rest of the code in the test program so that I could isolate where my issue is. This is what leads me to think it is a problem in the constructors. I downloaded the valgrind tool, never used it before but here is what it gave me:



==5131== Memcheck, a memory error detector.
==5131== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==5131== Using LibVEX rev 1884, a library for dynamic binary translation.
==5131== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==5131== Using valgrind-3.4.1-Debian, a dynamic binary instrumentation framework.
==5131== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==5131== For more details, rerun with: -v
==5131==
==5131== Invalid free() / delete / delete[]
==5131== at 0x4C260AD: operator delete(void*) (vg_replace_malloc.c:342)
==5131== by 0x400943: MyString::~MyString() (in /home/brad/project1/test2)
==5131== by 0x4009D6: main (in /home/brad/project1/test2)
==5131== Address 0x400acd is not stack'd, malloc'd or (recently) free'd
==5131==
==5131== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 8 from 1)
==5131== malloc/free: in use at exit: 0 bytes in 0 blocks.
==5131== malloc/free: 0 allocs, 1 frees, 0 bytes allocated.
==5131== For counts of detected errors, rerun with: -v
==5131== All heap blocks were freed -- no leaks are possible.



Any advice is greatly appreciated. Should I be in some way deleting old memory when creating the initial reference to my strings in the constructors? I've tried what I thought would do that but didn't have any different results. What I tried was:



char* org = storedValue;
storedValue = "";
delete org;


On a side note, can anyone recommend a decent text book for c++? I'm not too satisfied with the level of detail in the one I have.

oracleguy
09-09-2009, 03:28 PM
You are doing what is called a shallow copy in your constructors and assignment operator. You need to do a deep copy.

Shallow copy:


MyString::MyString(char * str)
{
storedValue = str;
}


Deep copy:


MyString::MyString(char * str)
{
storedValue = new char[strlen(str) + 1];
strcpy(storedValue, str);
}


The reason for the difference is that in a shallow copy, the string is pointing to the whatever is passed in. So if that pointer goes away, the pointer in your string class will be invalid.

You need to fix the rest of the constructors and your assignment operator in a similar fashion. Does that make sense?

Also let me see your header file, why is char * storedValue ; in your CPP? If there is a variable called that in your class, that storedValue declaration in your cpp isn't being used.



char* org = storedValue;
storedValue = "";
delete org;


This isn't how pointers work. When you assign a string literal to a pointer, you can't delete it. Because that string literal is on the stack, not the heap. You only delete memory created on the heap with the 'new' command.

brad211987
09-09-2009, 03:44 PM
Thanks again! Memory issues are resolved, and I took the storedValue declaration out of the CPP file, as it is already in the header file. Learned more from your few posts than 5 chapters of "C++ for Java Programmers". Not a book I would recommend for someone learning C++ in depth after learning other languages for a long time. I think a trip to the bookstore is in my future.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum