I have a problem to access a base class member variable from a derived class thru a interface containing 2 virtual functions. The main purpose is that I need to work with these classes at 2 different programn stages.
First stage is to fill an array with text snippets / sentences thru the ArrayStemmedSnippet class
The second stage, at a later point in the program, is getting items from the sentences array/snippet array defined in the base class thru the SuffixableElement interface class.
I have the strong feeling I am missing some basics here. I think there is a basic design or logic error. Also i have to admit, that I am not a C++ pro, means I am still a C++ beginner, So please bear with me....
Let me show you the code I have:
The class definition:
using namespace std;
// --- class represents a stemmed term of a StemmedSentence object
class StemmedTerm {
private:
string _word;
string _stemmed;
public:
StemmedTerm(string word, string stemmed);
~StemmedTerm();
// --- Implementation of StemmedTerm interface
string getTerm();
string getStemmed();
};
class StemmedSentence;
class SuffixableElement;
// --- a snippet containing stemmed sentences
class ArrayStemmedSnippet {
friend class StemmedSentence;
public:
ArrayStemmedSnippet();
ArrayStemmedSnippet(Array snippetTerms);
~ArrayStemmedSnippet();
SuffixableElement * getSentence(int n);
int size() const;
private:
Array snippet;
Array sentences;
};
// --- a stemmed sentence from ArrayStemmedSnippet
class StemmedSentence : public ArrayStemmedSnippet {
public:
StemmedSentence(ArrayStemmedSnippet *p);
StemmedSentence(const int start, const int end);
virtual ~StemmedSentence();
virtual void * get(int index) const;
virtual int size() const;
private:
int _start;
int _end;
ArrayStemmedSnippet *parent;
};
// --- interface to access a stemmed sentence and its size
class SuffixableElement {
public:
virtual ~SuffixableElement() = 0;
virtual void * get(int index) const = 0;
virtual int size() const = 0;
};
The implementation:
using namespace std;
StemmedSentence::StemmedSentence(const int start, const int end)
: _start(start), _end(end) {
}
StemmedSentence::StemmedSentence(ArrayStemmedSnippet *p)
: parent( p ) {
}
StemmedSentence::~StemmedSentence() {
}
// --- implementation interface SuffixableElement
void * StemmedSentence::get(int index) const {
if (index == (size() - 1)) {
return NULL; // --- End of string (sentence)
}
// get the stemmed term from snippets array in ArrayStemmedSnippet class
// is null, because array is not accessable thru the Suffixable iFace / eg not defined
return snippet[ _start + index ];
}
// --- implementation interface SuffixableElement
int StemmedSentence::size() const {
return _end - _start + 2;
}
// --- add array of snippet terms to sentences. NULL represents end of sentence
ArrayStemmedSnippet::ArrayStemmedSnippet() { }
ArrayStemmedSnippet::ArrayStemmedSnippet(Array snippetTerms)
: snippet( snippetTerms ) {
int index = 0;
for (int i = 0; i < snippetTerms.getLength(); i++) {
if (snippetTerms[ i ] == NULL) {
sentences.append( new StemmedSentence(index, i - 1 ));
index = i + 1;
}
}
}
ArrayStemmedSnippet::~ArrayStemmedSnippet() {
for (int i = 0; i < sentences.getLength(); i++) {
delete sentences[i];
}
}
int ArrayStemmedSnippet::size() const {
return sentences.getLength();
}
// --- returns n-th sentence of this snippet
SuffixableElement * ArrayStemmedSnippet::getSentence(int n) {
StemmedSentence( this ); // --- just a try: try passing base instance to derived class
return (SuffixableElement*)sentences[ n ];
}
The main body:
int main() {
// Sentence 1:
Array stemmed;
StemmedTerm *st1 = new StemmedTerm( "Mouse", "Mouse" );
StemmedTerm *st2 = new StemmedTerm( "ate", "ate" );
StemmedTerm *st3 = new StemmedTerm( "cheese", "cheese" );
stemmed.append( st1 );
stemmed.append( st2 );
stemmed.append( st3 );
stemmed.append( NULL ); // ---- end of snippet sentence
// Sentence 2:
StemmedTerm *st21 = new StemmedTerm( "Cat", "Cat" );
StemmedTerm *st22 = new StemmedTerm( "ate", "ate" );
StemmedTerm *st23 = new StemmedTerm( "cheese", "cheese" );
StemmedTerm *st24 = new StemmedTerm( "too", "too" );
stemmed.append( st21 );
stemmed.append( st22 );
stemmed.append( st23 );
stemmed.append( st24 );
stemmed.append( NULL ); // ---- end of snippet sentence
// ok -- one stemmedsnippet with 2 sentences
ArrayStemmedSnippet ass( stemmed );
// do some sother stuff ... later in the program ....
// --- get elements and size info thru SuffixableElements interface
SuffixableElement *currentElement = (SuffixableElement *)ass.getSentence(1);
cout << "cur. element size=" << currentElement->size() << endl;
StemmedTerm *st = (StemmedTerm*)currentElement->get(2, ass);
string str = st->toString();
cout < "second word is=" << str << endl;
delete st1;
delete st2;
delete st3;
delete st21;
delete st22;
delete st23;
delete st24;
return 1;
}
I skipped some function from above (toString() and other not relevant fct) to keep the
code as short as possible.
So the main problem is when I call
SuffixableElement * currentElement = (SuffixableElement *)ass.getSentence(1);
// --- this works fine!
cout << "cur. element size=" << currentElement->size() << endl;
// --- does not work, because snippet array of base class is uninitalized coming thru the
// --- interface ....
// --- Also passing the instance of the base class ArrayStemmedSnippet with the
// --- getSenctence() Fct does not help.
StemmedTerm * st = (StemmedTerm *)currentElement->get(2); // should return "cheese"
string str = st->toString();
cout << "str=" << str << endl;
What do I have to to that the snippet array is accessable thru the get(int index) call
with the SuffixableElement interface. The size() Fct is no problem, since I instanciated the derived class and access local members _start/_end.
Also StemmedSentence class as a nested class within ArrayStemmedSnippet is not working, unlike Java (I think) C++ wont let me access objects of ArrayStemmedSnippet like that.So I am sure I have some basic misunderstanding.
What I am missing???
Any help is greatly appreciated!!
// --- returns n-th sentence of this snippet
SuffixableElement* ArrayStemmedSnippet::getSentence(int n) {
// ...
return (SuffixableElement*)sentences[ n ];
}
'sentences' is an array of objects of the StemmedSentence class. StemmedSentence is not derived from SuffixableElement, that is it does not provide that interface.
Try the following:
class StemmedSentence : public ArrayStemmedSnippet, public SuffixableElement {
// ...
};
and
SuffixableElement* ArrayStemmedSnippet::getSentence(int n) {
StemmedSentence* sentence = sentences[ n ];
sentence->setParent(this);
return sentence;
}
If SuffixableElement is your interface, then StemmedSentence must derive from it.
Related
I am struggling to find the correct format for initializing a (private) array within a class and getting/setting the values from outside the class.
My code is semi-functional, but feels awkward in incorrectly formatted.
It is returning only the first element of the array, I want it to return all the contents. Read code comments for additional details.
Note: This is (a very small part of) a project I am working on for school -- an array must be used, not a vector or list.
student.h
class Student {
public:
// Upon researching my issue, I read suggestions on passing pointers for arrays:
void SetDaysToCompleteCourse(int* daysToCompleteCourse[3]);
int* GetDaysToCompleteCourse(); // Ditto # above comment.
private:
int daysToCompleteCourse[3];
student.cpp
#include "student.h"
void Student::SetDaysToCompleteCourse(int* daysToCompleteCourse) {
// this->daysToCompleteCourse = daysToCompleteCourse; returns error (expression must be a modifiable lvalue)
// Feels wrong, probably is wrong:
this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
this->daysToCompleteCourse[1] = daysToCompleteCourse[1];
this->daysToCompleteCourse[2] = daysToCompleteCourse[2];
}
int* Student::GetDaysToCompleteCourse() {
return daysToCompleteCourse;
}
ConsoleApplication1.cpp
#include "pch.h"
#include <iostream>
#include "student.h"
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
int* ptr = daysToCompleteCourse;
student.SetDaysToCompleteCourse(ptr);
std::cout << *student.GetDaysToCompleteCourse(); // returns first element of the array (1).
}
I gave this my best shot, but I think I need a nudge in the right direction.
Any tips here would be greatly appreciated.
I would say:
// student.h
class Student
{
public:
// If you can, don't use numbers:
// you have a 3 on the variable,
// a 3 on the function, etc.
// Use a #define on C or a static const on C++
static const int SIZE= 3;
// You can also use it outside the class as Student::SIZE
public:
void SetDaysToCompleteCourse(int* daysToCompleteCourse);
// The consts are for "correctness"
// const int* means "don't modify this data" (you have a setter for that)
// the second const means: this function doesn't modify the student
// whithout the const, student.GetDaysToCompleteCourse()[100]= 1 is
// "legal" C++ to the eyes of the compiler
const int* GetDaysToCompleteCourse() const; // Ditto # above comment.
Student()
{
// Always initialize variables
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= 0;
}
}
private:
int daysToCompleteCourse[SIZE];
// On GCC, you can do
//int daysToCompleteCourse[SIZE]{};
// Which will allow you not to specify it on the constructor
};
// student.cpp
void Student::SetDaysToCompleteCourse(int* newDaysToCompleteCourse)
{
// It's not wrong, just that
// this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
// use another name like newDaysToCompleteCourse and then you can suppress this->
// And use a for loop
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= newDaysToCompleteCourse[i];
}
}
const int* Student::GetDaysToCompleteCourse() const
{
return daysToCompleteCourse;
}
// main.cpp
#include <iostream>
std::ostream& operator<<(std::ostream& stream, const Student& student)
{
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
stream << toShow[i] << ' ';
}
return stream;
}
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
// You don't need this
//int* ptr = daysToCompleteCourse;
//student.SetDaysToCompleteCourse(ptr);
//You can just do:
student.SetDaysToCompleteCourse(daysToCompleteCourse);
// On C++ int* is "a pointer to an int"
// It doesn't specify how many of them
// Arrays are represented just by the pointer to the first element
// It's the FASTEST and CHEAPEST way... but you need the SIZE
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
std::cout << toShow[i] << ' ';
// Also works:
//std::cout << student.GetDaysToCompleteCourse()[i] << ' ';
}
std::cout << std::endl;
// Or you can do: (because we defined operator<< for a ostream and a Student)
std::cout << student << std::endl;
}
You can check out it live here: https://ideone.com/DeJ2Nt
I am currently creating a program that will help me to learn new vocabulary. The workflow of the program is going to be ruled by the VocabularyTester class and it contains a list of objects of class WordPair stored in a vector array.
class VocabularyTester
{
private:
std::vector<WordPair> wordList;
std::vector<WordPair> failedPairs;
std::vector<WordPair> passedPairs;
WordPair recentPair;
public:
VocabularyTester();
void run();
void loadWordList(std::wstring& vocabularyRaw);
/*
other parts of the code
*/
};
/* the function i'm having a problem with */
void VocabularyTester::loadWordList(std::wstring& vocabularyRaw)
{
std::wstring rawPair;
unsigned int iterator = 0, prevIterator = 0;
for (;;)
{
iterator = vocabularyRaw.find(L"\r\n", iterator);
if (iterator == std::string::npos)
{
break;
}
rawPair = vocabularyRaw.substr(prevIterator, iterator);
wordList.emplace_back(rawPair); /*there occurs the read access violation exception*/
prevIterator = iterator;
}
}
When the execution reaches wordList.emplace_back(rawPair), the read access violation exception is thrown, exactly here:
/* vector header file */
bool _Has_unused_capacity() const _NOEXCEPT
{ // micro-optimization for capacity() != size()
return (this->_Myend() != this->_Mylast());
}
WordPair is a pair of 2 words, it has 2 string members: leftWord for a word in native language, rightWord for a word in language someone would like to learn. Here's the constructor of the object I am using to add it to the vector array:
WordPair::WordPair(std::wstring& rawPair)
{
std::wstring separator = L" - ";
size_t separatorPosition = rawPair.find(separator);
std::wstring leftWord = rawPair.substr(0, separatorPosition);
std::wstring rightWord = rawPair.substr(separatorPosition + separator.length());
this->leftWord = leftWord;
this->rightWord = rightWord;
}
Thanks for your help.
I'm having a problem that I haven't found an answer for in a week now. I have a dynamic array class and it has a method to add string values to it. It's supposed to represent an inventory you can add items to. However, I find that the changes made in the method to the private values of the class element aren't "updated" when I try to call for a print-method for the class element "backpack" later in the main(). I think this might be a problem due to referencing issues, but I've seen this work when a class hasn't been in a different module.
My "backpack" module print and add methods:
const int INITIAL_SIZE = 5;
Inventory::Inventory():
array_(new string[INITIAL_SIZE]),
max_space_(INITIAL_SIZE),
used_space_(0) {}
void Inventory::add(string item){
if ( size() == max_space_ ) {
string* new_array = new string[2 * max_space_];
for ( int i = 0; i < size(); ++i ) {
new_array[i] = array_[i];
}
delete [] array_;
array_ = new_array;
max_space_ = 2 * max_space_;
}
array_[used_space_] = item;
++used_space_;
}
void Inventory::print() {
for ( int i = 0; i < size(); ++i ) {
cout << array_[i] << endl;
}
}
The main():
Inventory inv;
string input;
while (cout << "input> "
and getline(cin,input)){
add_to_bag(input,inv);
So the point is you reset the inventory when you give it new contents. The function add_to_bag(); is:
void add_to_bag(string input, Inventory inv){
const string WHITESPACE1_REGEX = "[[:space:]]*";
const string WHITESPACE2_REGEX = "[[:space:]]+";
const string WORD_REGEX = "[[:alpha:]_]+";
const string LINE_REGEX =
WHITESPACE1_REGEX +
WORD_REGEX +
"(" +
WHITESPACE2_REGEX +
WORD_REGEX +
")*" +
WHITESPACE1_REGEX;
regex line_reg(LINE_REGEX);
regex word_regex(WORD_REGEX);
string line = input;
if ( regex_match(line, line_reg) ) {
sregex_iterator iter(line.begin(), line.end(), word_regex);
sregex_iterator end;
while ( iter != end ) {
inv.add(iter->str());
++iter;
}
} else {
cout << "Error: unknown inventory contents." << endl;
}
}
Your problem is:
void add_to_bag(string input, Inventory inv);
You pass a copy of the Inventory object to add_to_bag. You modify that copy ... and then it gets thrown away. The fix is to pass by reference:
void add_to_bag(string input, Inventory &inv);
Incidentally, in real-life code, I would strongly advise the use of std::vector<std::string> rather than "roll your own". There are a number of tricky exception handling issues you have got wrong here - and unless Inventory doesn't have a destructor (implying a memory leak), or does have a correct copy constructor I would have expected you to run into "double free" issues. (Read about "The Rule of Three".)
A simple way to design your class would be as follows:
class Inventory {
private:
std::vector<std::string> items_;
public:
Inventory(){}
~Inventory(){}
void addItem( const std::string& item ) {
items_.push_back( item );
}
void printInventory() const {
int idx = 0;
for (; idx < items_.size(); ++idx ) {
std::cout << items_[idx] << std::endl;
}
}
void clearInventory() {
items_.clear();
}
};
And as for your problem Martin Bonner had already answered it with the modifying of the copy and the removal of it afterwards and the other issues with the memory management.
//this is my main Method ,this was an experiment to understand shared pointer usage
#include <iostream>
#include "shared_ptrtestA.h"
int main(int argc, const char * argv[]) {
// declare a shared pointer to the class
sharedptr_testA* A = new sharedptr_testA(5);
//class has a vector , push back a new instance into the vector
A->mvect.push_back(sharedptr_testA::Aptr(new sharedptr_testA::testA(
sharedptr_testA::sharedptr_testB::Create(1) , sharedptr_testA::sharedptr_testC::Create(1)
)));
//class has a vector , push back a new instance into the vector
A->mvect.push_back(sharedptr_testA::Aptr(new sharedptr_testA::testA(
sharedptr_testA::sharedptr_testB::Create(2),sharedptr_testA::sharedptr_testC::Create(2)
)));
//iterate the vector populated above
for(std::vector<sharedptr_testA::Aptr>::iterator it = A->mvect.begin() ;
it!= A->mvect.end() ; it++)
{
// get members from the vector iterator
sharedptr_testA:: sharedptr_testB::Bptr B = (*it)->mb;
sharedptr_testA:: sharedptr_testC::Cptr C = (*it)->mc;
// print contents of members
for(int i = 0 ; i < B->m_size ; i++)
{
std::cout<<B->bytes[i]<<'\t';
}
std::cout <<std::endl;
for(int i = 0 ; i < C->m_size ; i++)
{
std::cout<<C->bytes[i]<<'\t';
}
std::cout <<std::endl;
}
}
//this was the main method above and the expected output was
B
C
BB
CC
The structure of the classes used are
//Header File
#ifndef shared_ptrtest_shared_ptrtestA_h
#define shared_ptrtest_shared_ptrtestA_h
#include <memory>
#include <functional>
#include <vector>
class sharedptr_testA
{
public:
// constructor and destructor
sharedptr_testA(int vsize);
~sharedptr_testA();
// an internal class member defined
class sharedptr_testB
{
public:
typedef std::shared_ptr<sharedptr_testB> Bptr;
//static create method
static Bptr Create(int msize)
{
return Bptr(new sharedptr_testB(msize));
}
//members
int m_size;
char *bytes;
//private contructor
private:
sharedptr_testB(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[size]= 'B';
}
};
//class c has same structure as class B above
class sharedptr_testC
{
public:
typedef std::shared_ptr<sharedptr_testC> Cptr;
static Cptr Create(int msize)
{
return Cptr(new sharedptr_testC(msize));
}
int m_size;
char *bytes;
private:
sharedptr_testC(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[size]= 'C';
}
};
// struct containing shared pointers to classes defined above
struct testA
{
testA(sharedptr_testB::Bptr B, sharedptr_testC::Cptr C)
{
mb = B;
mc = C;
}
sharedptr_testB::Bptr mb;
sharedptr_testC::Cptr mc;
};
typedef std::shared_ptr<testA> Aptr;
std::vector<Aptr> mvect;
};
#endif
//The short cpp file for the above class contains only constructor and destructor
#include "shared_ptrtestA.h"
sharedptr_testA::sharedptr_testA(int vsize)
:mvect(vsize)
{
}
sharedptr_testA::~sharedptr_testA()
{
}
What is wrong in the above code ? I wrote this to understand shared pointer usage
You have two bugs in your program:
The loops in constructors of sharedptr_testB and sharedptr_testC use size instead of i for indexing. It should be:
sharedptr_testB(int size)
{
m_size = size;
bytes = new char[size];
for(int i = 0 ; i < size ; i++)
bytes[i]= 'B';
}
(DTTO) for sharedptr_testC)
You start with a vector of size 5, which means it stores five null pointers. Then you append two elements to it (size 7, five nulls + two valid pointers). The you iterate over it, dereferencing each pointer. This of course crashes, since there are nulls at the beginning. Simply initialise the vector as empty.
sharedptr_testA* A = new sharedptr_testA(0);
With these two fixes, the code works.
Side notes 1 (C++):
The code is next to impossible to read. I strongly suggest you use a better naming scheme.
sharedptr_testB and sharedptr_testC leak memory. I understand it's just a learning excercise, I'd just like to point it out. You'd be better off with std::vector<char> in them instead of char*.
Side notes 2 (Stack Overflow):
If you have a crashing program, you should generally try to debug it yourself before asking an SO question. Stepping through the program through a debugger would easily have uncovered both the issues.
For simple data like ints or constants something like this would work
#include <iostream>
#include <vector>
using namespace std ;
typedef void FuncInt (int) ;
class GraphElementProto {
public:
void add (FuncInt* f)
{
FuncVec.push_back (f) ;
} ;
void call()
{
for (size_t i = 0 ; i < FuncVec.size() ; i++)
FuncVec[i] (i) ;
} ;
private:
vector<FuncInt*> FuncVec ;
} ;
static void f0 (int i) { cout << "f0(" << i << ")" << endl ; }
static void f1 (int i) { cout << "f1(" << i << ")" << endl ; }
int main() {
GraphElementProto a ;
a.add (f0) ;
a.add (f1) ;
a.call() ;
}
So now imagine we work with some data buffer like char.
We have threads that wait for data pointers and on appearance of that pointers want to change data at the same time. So we would need to create copy's of that data and give to each subscriber pointer to his own copy.
So how to do such thing? (sorry C++ nube - code is only thing I can understand)
Consider the similarities between each node of the graph that you describe and create a class for them (class GraphElement below). It should encapsulate its relationship to its child nodes, and it should do something locally with any incoming messages (function localAction). You should then derive classes that represent specific variations - such as the image generator you mention - and change the local action. Each class may take a copy of the original message, or change it as you need.
In my example code here I have create the default graph node - GraphNode - and made it simply print incoming messages before passing them to its child nodes. I have used a string object for the incoming message - a lot nicer than a plain old C char * array [example: you can derive a string from char * when message2 is created in the code below]. I have made those object const references as its cheap, fast, and never changes the original.
I have derived a class called CatNode as an example of the variation you need. Objects of this type contain a history of all messages, and print out that history when a new message arrives. Not very useful - but a good example none the less. This demonstrates how each node may do anything to a copy of the original message - rewrite localAction(). It also passes that history to any child nodes - rewrite incomingMessage with a change to the parameter passed to deliverMessage().
#include <vector>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::vector;
using std::string;
class GraphNode
{
public:
GraphNode( string & name ) : mChildren(), mName(name) {}
GraphNode( const char * const name ) : mChildren(), mName(name==NULL?"":name) {}
virtual void incomingMessage( const string & str ) {
localAction(str); // This node is to do something.
deliverMessage(str); // Child nodes are to do things too.
}
void addChild( GraphNode * child ) {
mChildren.push_back( child );
}
protected:
// Rewrite this function for child classes who are to do different things with messages.
virtual void localAction( const string & str ) {
cout << mName << " : " << str << endl;
}
void deliverMessage( const string & str ) {
vector<GraphNode*>::iterator itr = mChildren.begin();
for( ; itr != mChildren.end(); ++itr )
(*itr)->incomingMessage(str);
}
// Data members
vector<GraphNode*> mChildren;
string mName;
}; // [ GraphNode ]
class CatNode : public GraphNode
{
public:
CatNode( string & name ) : GraphNode(name), mHistory() {}
CatNode( const char * const name ) : GraphNode(name), mHistory() {}
virtual void incomingMessage( const string & str ) {
localAction(str);
deliverMessage(mHistory);
}
protected:
virtual void localAction( const string & str ) {
mHistory += str;
cout << mName << " : " << mHistory << endl;
}
// Data members
string mHistory;
}; // [ CatNode ]
main()
{
// root -> childA
GraphNode root("Root Node");
CatNode childA("Child A");
root.addChild( &childA );
root.incomingMessage("Message1");
cout << endl;
// root -> childA -> childC
// \-> childB
GraphNode childB("Child B");
root.addChild( &childB );
GraphNode childC("Child C");
childA.addChild( &childC );
string message2("Message2");
root.incomingMessage(message2);
} // [ main ]