You are not logged in.
Pages: 1
I'm new to C++, I usually use Java. So my question is: I have a pure virtual class that I want to use as an interface, the class is
class DatabaseRecord {
public:
virtual std::string getInsert() = 0;
virtual std::string getTable() = 0;
};
this is only declared in a header file I have no cpp file for this class. I then have a sub class such as
class State : public DatabaseRecord {
private:
std::string name;
public:
State();
virtual ~State();
std::string getInsert();
std::string getTable();
};
this again is a header file. My cpp file for this header looks like,
State::State(){ name = "Test"; }
State::~State(){}
std::string State::getInsert() {
std::stringstream ss;
ss << "Test " << name << "T";
return ss.str();
}
std::string State::getTable() {
std::stringstream ss;
ss << "CREATE " << name;
return ss.str();
}
The problem is that when I call either method getInset or getTable the variable "name" is empty.
I mean when I print out the return string it dosent print the contents of name "Test".
Any Help will be greatly appreciated.
Offline
So what you're saying is that you see, for example,
Test T
when you print out the return value of getInsert(), instead of the expected
Test TestT
correct?
Using the code you're provided here works as expected for me, with this main:
#include "State.h"
#include <iostream>
int main()
{
State s;
std::cout << s.getInsert() << std::endl;
DatabaseRecord* db = new State();
std::cout << db->getInsert() << std::endl;
delete db;
}
Last edited by Cerebral (2007-12-03 19:29:47)
Offline
Well here is what am doing I first create an object of type DatabaseRecord such as, and then push it into a List which is declared as std::list<DatabaseRecord *> records;
State s;
records.push_back(&s);
The in another segment of code I do this;
if(!records.empty()) {
std::list<DatabaseRecord *>::const_iterator it;
for(it = records.begin(); it != records.end(); ++it) {
std::cout << (*it)->getInsert() << std::endl;
}
records.clear();
}
but it doesn't work.
The implementation is a DLL file for Windows and it have export declarations for methods such as;
AREXPORT std::string getInsert();
I left them out for the sake of simplicity, do you think this has something to do with this?
I really appreciate your help. Thank you
Offline
Well here is what am doing I first create an object of type DatabaseRecord such as, and then push it into a List which is declared as std::list<DatabaseRecord *> records;
State s;
records.push_back(&s);The in another segment of code I do this;
if(!records.empty()) {
std::list<DatabaseRecord *>::const_iterator it;
for(it = records.begin(); it != records.end(); ++it) {
std::cout << (*it)->getInsert() << std::endl;
}
records.clear();
}but it doesn't work.
I think this may be the source of your problem - especially if you do it exactly the way you describe.
For example, this will NOT work (for the reasons indicated in the comments):
void push_back_new_state() {
State s; // allocate a new State object, local to this block
records.push_back(&s);
} // ONOZ! The block ends, State s is destroyed and &s is no longer valid!
void read_states() {
if(!records.empty()) {
std::list<DatabaseRecord *>::const_iterator it;
for(it = records.begin(); it != records.end(); ++it) {
std::cout << (*it)->getInsert() << std::endl;
}
records.clear();
}
}
int main() {
push_back_new_state(); // State s is destroyed when this call ends
read_states(); // This call will try to read from the destroyed State s. BAD!
}
What you need to do is allocate on the heap, not the stack:
void push_back_new_state() {
// allocate a new State object on the heap - object is not destroyed at the end of this block
State * s = new State();
records.push_back(s);
} // Woot! the new state object isn't destroyed!
void read_states() {
if(!records.empty()) {
std::list<DatabaseRecord *>::const_iterator it;
for(it = records.begin(); it != records.end(); ++it) {
std::cout << (*it)->getInsert() << std::endl;
delete (*it); // make sure we free the memory! Don't want a leak!
}
records.clear();
}
}
int main() {
push_back_new_state(); // State s is not destroyed when this call ends
read_states(); // This call will read from the State s allocated on the heap. Fine and dandy!
}
Offline
I could kiss you right now. :D:D:D
You just solve my problem, i waisted around 12 hours in total searching around in google.
I will just blame my ignorance on Java.
But, seriously thanks a million.
Offline
No prob - memory management is one of the tricky aspects you've gotta get used to when moving to C++ from Java, where you don't have to manage anything. Good luck with your app.
Offline
For the record, it's probably much simpler for you to use boost::ptr_list<DatabaseRecord> instead of std::list<DatabaseRecord*> as it will manage memory management for you (yay!).
And another thing... list is an expensive container for what you're doing. Try a vector or deque (yay deque!). Those two should actually be more of a default choice than using std::list.
Offline
For the record, it's probably much simpler for you to use boost::ptr_list<DatabaseRecord> instead of std::list<DatabaseRecord*> as it will manage memory management for you (yay!).
I guess I really need to learn boost, don't I? It seems to have many things that are made of win.
Offline
Not sure if you are thinking of mixing different C++ compilers (one compiling the DLL and another compiling the program which then will load the DLL). If you are going to do that, then it might be a good idea to read more about name mangling.
Last edited by PJ (2007-12-03 21:19:16)
Offline
phrakture wrote:For the record, it's probably much simpler for you to use boost::ptr_list<DatabaseRecord> instead of std::list<DatabaseRecord*> as it will manage memory management for you (yay!).
I guess I really need to learn boost, don't I? It seems to have many things that are made of win.
Yeah. boost::ptr_vector<T> is really just a std::vector<boost::shared_ptr<T>> (not exactly, though), and boost::shared_ptr is just a simple reference counted pointer container that deletes when the ref count hits 0. You can also provide custom deleters, which makes it work great with C functions. For instance...
boost::shared_ptr<Display> dpy(XOpenDisplay(), XCloseDisplay);
Yay!
Offline
Thanks for your replies. Its working wonderful now. I also dint know about boost sounds cool. I will consider next time I work with C++.
Offline
Another thing you should be aware of - google "virtual destructor"
I don't know if you have learned about destructors, they are new in C++ from Java, but they are simply functions that are called when an object is deleted. As it is, you are calling the "default destructor", the destructor the compiler writes for you since you don't have one. The problem is that since you are storing pointers to DatabaseRecord objects, the DatabaseRecord destructor will be called instead of the State destructor.
To fix that, you simply create
virtual DatabaseRecord::~DatabaseRecord() { }
and override it wherever needed.
Offline
Pages: 1