SO I am trying to teach myself data structures in C++. To do so, I made an ArrayList class with a member variable arrayData with type int* and a get method to access values from that pointer. I come from a Java background and C++ OOP is sorta strange, especially with the separation of header and source files. At compile, I get, "error: 'int* ArrayList::arrayData' is not a static data member of 'class ArrayList'". I marked them with ArrayList:: to make them members of ArrayList, so why does this not mark them as such? Thank you so much if you can point me in the direction of how to access my variable.
ArrayList.cpp:
#include "ArrayList.h"
ArrayList::ArrayList(int size) {
arrayData = new int[size];
}
ArrayList::~ArrayList() {
delete arrayData;
}
int* ArrayList::get(int index) {
return (*(this.arrayData))[index];
}
int* ArrayList::arrayData;
ArrayList.h:
#define ARRAYLIST_H_
class ArrayList {
public:
ArrayList(int size);
~ArrayList();
int get(int index);
private:
int* arrayData;
};
#endif /* ARRAYLIST_H_ */
This line:
int* ArrayList::arrayData;
In the source file makes no sense. Compiler thinks you're referencing a static variable of ArrayList (because you've prepended with the class name). Remove this line.
You will be able to access arrayData from the other methods.
Also, use std::unique_ptr<int> instead of the raw pointer. Then your memory is guaranteed to be automatically released after use.
You have a few errors here.
First, your ArrayList.h include guards are incorrect.
#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_
class ArrayList {
public:
ArrayList(int size);
~ArrayList();
int get(int index);
private:
int* arrayData;
};
#endif /* ARRAYLIST_H_ */
Next, Your int ArrayList::get declaration and definition are inconsistent. There isn't a need for the int* ArrayList::arrayData; in your C++ file as well.
#include "ArrayList.h"
ArrayList::ArrayList(int size) {
arrayData = new int[size];
}
ArrayList::~ArrayList() {
delete arrayData;
}
int ArrayList::get(int index) {
return arrayData[index];
}
Related
I am a C++ newbie and I need help with a strange issue (or at least its strange to me)
I have a class as such:
class Myclass {
private:
int A;
// some other stuff...
public:
// constructor and stuff...
void setA(int a);
int* getA_addr();
};
void Myclass::setA(int a){
A = a;
};
int* Myclass::getA_addr(){
return &A;
};
Now, I want to modify A in main() and I am not using any other methods in the class (I did it by using extra methods and now I want to see how I can do it without using those extras). I have a function as such:
void change(int *ptr, int tmp){
*ptr = tmp;
};
In a call to this function, I do the passing as such: change(obj.getA_addr(), other arguments...) where obj is an instance of Myclass.
When done in this way, I receive no compilation errors but I also can't seem to modify A (of obj). As a debug effort, I tried to print the address of A (of obj) by directly calling getA_addr(). I saw that with every call, the function returns a different address. So I am assuming that I am not passing the intended address into the function.
I have no idea why this is happening and would like to know. Also, the way I'm trying to do this is most likely not at all accurate so please, if you can provide a solution, it would be appreciated. Thanks.
EDIT: Here's the most minimal code I could come up with that reproduces the error
#include <iostream>
#define MAX_SIZE 10
using namespace std;
class Student {
private:
int mt1;
public:
Student();
void setMt1(int in_mt1);
int* getMt1();
};
Student::Student() {};
void Student::setMt1(int in_mt1) { mt1 = in_mt1; };
int* Student::getMt1(){ return &mt1; };
class Course {
private:
Student entries[MAX_SIZE];
int num;
public:
Course();
void addStudent(Student in_student);
Student getStudent(int index);
};
Course::Course(){ num = 0; };
void Course::addStudent(Student in_student){
entries[num] = in_student;
num++;
};
Student Course::getStudent(int index){ return entries[index]; };
int main() {
void updateStudentScore(int *uscore, int newscore);
Course mycourse;
Student tmp_student;
tmp_student.setMt1(60);
mycourse.addStudent(tmp_student);
cout<<mycourse.getStudent(0).getMt1()<<"\t"<<*mycourse.getStudent(0).getMt1()<<endl;
updateStudentScore(mycourse.getStudent(0).getMt1(), 90);
cout<<mycourse.getStudent(0).getMt1()<<"\t"<<*mycourse.getStudent(0).getMt1()<<endl;
return 0;
}
void updateStudentScore(int *uscore, int newscore){
*uscore = newscore;
};
I am fairly certain that my understanding of pointers and passing-by-whatevers is lacking and the way I defined functions here is creating the bug. I am sorry to inconvenience you guys. I would appreciate it if you could take a look.
Looking at your student/course code, i notice that Course::getStudent returns a Student rather than a Student &. Basically, that means each time you call getStudent(x), you get a temporary copy of student x, whose getMt1 function will give you a pointer to a temporary field, and any changes you make won't even survive past that statement.
If you have getStudent return a reference or pointer instead, your changes should persist to the Student contained in the array. (They still won't affect tmp_student, though, because addStudent copied it to add it to the array. If you want that reliably, then you need to redo quite a bit of stuff.)
HelloI got a problem when i compiled my program.
Why the pointer intArray gives different addresses in constructor and member function display() in same object?Thank you!
#include<iostream>
using namespace std;
class MyClass
{ private:
int* intArray;
int arraySize;
public:
MyClass(int*,int);
~MyClass()
{delete []intArray;};
void display();
};
MyClass::MyClass(int intData[],int arrSize)
{ int *intArray = new int[arrSize];
cout<<intArray<<" "<<endl;
};
void MyClass::display()
{ cout<<intArray<<" "<<endl;
}
int main()
{ int Data[10]={9,8,7,6,5,4,3,2,1,0};
MyClass obj1(Data,10);
obj1.display();
}
In the constructor, you declare a local variable which hides the member. Both members are left uninitialised, so calling display will show the uninitialised value.
You probably want something along the lines of
MyClass::MyClass(int intData[],int arrSize) :
intArray(new int[arrSize]),
arraySize(arrSize)
{
// assuming the input array specifies initial values
std::copy(intData, intData+arrSize, intArray);
}
Since you're dealing with raw pointers to allocated memory, remember to follow the Rule of Three to give the class valid copy semantics. Then, once you're happy with your pointer-juggling skills, throw it away and use std::vector instead.
I'm new to the site (and to programming) so I hope I post this question appropriately and under all the proper guidelines of the site. Ok, here it goes:
So I pretty new to C++ and am trying to create classes for a program. I have to construct "container and entity classes", but where I'm struggling is trying to nail down the proper syntax for my getter and setter functions in the container class. So here's the code I have so far:
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
using namespace std;
const int MAX_STUDENTS=100;
const int MAX_COURSES=25;
const int NAME_SIZE=30;
const int COURSE_COLUMNS=4;
const int GRADE_ROWS=10;
//Entity Classes
class Course
{
//Two private member variables
private:
string courseText;
int courseID;
public:
//Constructor
Course(void)
{
//Just providing initial value to the two object variables
courseText;
courseID=-1;
}
//Setters and Getters for each variable
string getCourseText(){
return courseText;}
void setCourseText(string userEnteredText){
courseText = userEnteredText;}
int getCourseID(){
return courseID;}
void setCourseID(int userEnteredID){
courseID = userEnteredID;}
};
class Student
{
//Private member variables
private:
string studentText;
int studentID;
int** coursesAndGrades;
int enrolledCoursesCount;
int timesReallocatedColumns;
int timesReallocatedRows;
public:
//Constructor
Student(void)
{
//Just providing initial value to the object variables
studentText;
studentID=-1;
coursesAndGrades = new int*[GRADE_ROWS+1];
for(int i=0;i<(GRADE_ROWS+1);i++)
{
coursesAndGrades[i] = new int[COURSE_COLUMNS];
}
enrolledCoursesCount=0;
timesReallocatedColumns=0;
timesReallocatedRows=0;
}
//Setters and Getters for each variable
string getStudentText(){
return studentText;}
void setStudentText(string userEnteredText){
studentText = userEnteredText;}
int getStudentID(){
return studentID;}
void setCourseID(int userEnteredID){
studentID = userEnteredID;}
int getCoursesAndGrades(int gradeRow, int courseColumn){
return coursesAndGrades[gradeRow][courseColumn];}
void setCoursesAndGrades(int gradeRow, int courseColumn, int entry){
coursesAndGrades[gradeRow][courseColumn]=entry;}
int getEnrolledCoursesCount(){
return enrolledCoursesCount;}
void setEnrolledCoursesCount(int enrolledCount){
enrolledCoursesCount = enrolledCount;}
int getTimesReallocatedColumns(){
return timesReallocatedColumns;}
void setTimesReallocatedColumns(int reallocColumnCount){
timesReallocatedColumns = reallocColumnCount;}
int getTimesReallocatedRows(){
return timesReallocatedRows;}
void setTimesReallocatedRows(int reallocRowCount){
timesReallocatedRows = reallocRowCount;}
};
Now, I've got a container class called GradeBook which contains dynamically allocated arrays of these two entity class objects.
class GradeBook
{
private:
Course* courses;
Student* students;
public:
//Constructor
GradeBook(void)
{
courses = new Course [MAX_COURSES];
students = new Student [MAX_STUDENTS];
}
}
I'm trying to figure out the proper way to translate the setter and getter functions from my entity classes to the container class so I can change individual elements of each class object in the dynamically allocated array. These changes will happen in more public member functions in the container class, but I'm completely stumped. I hope this question makes sense, and I'm not looking for anyone to write all of the setters and getters for me, I just need someone to point me in the proper direction for the syntax. Thanks everyone who made it through this!
If you will have something like this:
class GradeBook
{
public:
...
Student& student(int idx) { /*some boundary check here*/
return students[idx]; }
}
then you can use that method as:
GradeBook theBook;
...
auto idOfFirstStudent = theBook.student(0).getStudentID();
You just need to decide what that student() method shall return: it can return reference (as above) or pointer to student (instance). In later case you can return nullptr in case of out-of-bound errors. In first case the only reasonable option is to throw an error.
So there's no magic needed here, but you do need to decide how you want to do it. One way would be to just write something like:
void GradeBook::setCourseText(int i, const string &txt) {
courses[i].setCourseText(txt);
}
BTW, I would highly recommend using std::vector and at() rather than new.
This question was from "Thinking in C++" Vol-1, Chapter 5's exercise No.14:
Create a StackOfInt class (a stack that holds ints) using the
“Cheshire cat” technique that hides the low-level data structure you
use to store the elements in a class called StackImp. Implement two
versions of StackImp: one that uses a fixed-length array of int, and
one that uses a vector. Have a preset maximum size for the stack
so you don’t have to worry about expanding the array in the first
version. Note that the StackOfInt.h class doesn’t have to change with
StackImp.
Here is the header file (StackOfInt.h) I created:
#ifndef STACKOFINT_H
#define STACKOFINT_H
class StackOfInt
{
int size;
int curr_idx;
class StackImp;
StackImp* head;
public:
void initialize(int max);
void push(void* dat);
void* peek();
void* pop();
void cleanup();
};
#endif
However, for the implementation, I'm confused about how to handle the difference between array and vector. Here is what I came up with so far:
#include "StackOfInt.h"
#include "require.h"
#include <vector>
class StackOfInt::StackImp
{
int arrInt[50];
public:
void initialize()
{
for (int i = 0; i < 50; i++)
{
arrInt[i] = 0;
}
}
};
/*
class StackOfInt::StackImp
{
std::vector<int> vecInt;
}
*/
void StackOfInt::initialize(int max)
{
size = max;
curr_idx = 0;
head = 0;
StackImp* newImp = new StackImp;
newImp->initialize();
}
void StackOfInt::push(void* dat)
{
*(head+curr_idx) = dat;
curr_idx++;
}
void* Stack::peek(int idx)
{
require(head != 0, "Stack empty");
return head[idx];
}
void Stack::cleanup()
{
require(head == 0, "Stack not empty");
} ///:~
I think I'm on the wrong tracks, could anyone give me some hints on how to solve this problem?
What the book author has in mind, is that the StackOfInt class should not contain any other members besides a pointer to the implementation class. The necessary data members, be it an array + count variable or a vector, should be members of the implementation class.
So in the header, you'd have
class StackOfInt {
class StackImp;
StackImp* impl;
public:
void initialize();
void push(int dat);
int peek();
int pop();
void cleanup();
};
In the implementation file you'd have the implementation:
class StackOfInt::StackImp
{
public:
int count;
int array[100];
};
void StackOfInt::initialize()
{
impl = new StackImp;
impl->count = 0;
}
void StackOfInt::push(int dat)
{
impl->array[impl->count++] = dat;
}
//and other methods
Write another cpp file that uses the StackOfImp class. Compile the project and run the program to make sure everything works nicely :)
Now you can completely rewrite the implementation file for the StackOfInt to use a vector as the underlying type. Recompile the project. Note that the user of StackOfImp (the test code) does not have to be recompiled because nothing was changed in the header.
To read more about the technique that the author calls "Cheshire cat": Opaque pointer
Note that I don't understand your usage of void pointer. A StackOfInt should take and return integers.
Calling the implementation pointer head also seems to indicate some misunderstanding. This represents a pointer to the object that will actually contain the necessary members to implement the stack.
One way of handling that is to make the "impl" class polymorphic and use a factory to select the implementation at construction time.
I think the expectation is that you will have two different implementations in two separate cpp files, and you would include one or the other in the project in order to use it.
StackImplArr.cpp
class StackOfInt::StackImp
{
int arrInt[50];
}
StackImplVec.cpp
class StackOfInt::StackImp
{
std::vector<int> vecInt;
}
A more advanced use would declare a base class and derive the two implementations from it, allowing the implementation to be selected at runtime:
class StackOfInt::StackImp
{
virtual initialize() = 0;
}
class StackOfInt::StackImpArr : public StackOfInt::StackImp
{
int arrInt[50];
virtual initialize() { ... }
}
class StackOfInt::StackImpVec : public StackOfInt::StackImp
{
std::vector<int> vecInt;
virtual initialize() { ... }
}
void
StackOfInt::initialize( int max) {
head = condition ? new StackImpArr() : new StackImpVec();
}
So I am quite wary new to C++ and I really do not understand templates and how to use tham thow I rad wikipedia and started reading like 2000 pages long book on C++... So I am probably way 2 impatient but I wonder If using C++ templates we can make for example such simple class pair work with costume structures instead of chars.
#include <iostream>
#include <vector>
// Boost
#include <boost/thread.hpp>
#ifndef _IGraphElementBase_h_
#define _IGraphElementBase_h_
#pragma once
using namespace std ;
class IGraphElementBase {
public:
boost::thread GraphWorker;
mutable boost::mutex GraphItemMutex;
boost::condition_variable GraphItemMutexConditionVariable;
int SleepTime;
// Function for preparing class to work
virtual void Init(){ SetSleepTime(1);}
void SetSleepTime(int timeMS)
{
SleepTime = timeMS;
}
// Function for data update // word virtual makes it possible to overwrite it
virtual void updateData(){}
void StartThread()
{
GraphWorker = boost::thread(&IGraphElementBase::Call, this);
}
virtual void CleanAPI(){}
virtual void Clean()
{
GraphWorker.interrupt();
GraphWorker.join();
CleanAPI();
}
virtual void CastData(){}
//Here is a main class thread function in infinite loop it calls for updateData function
void Call()
{
try
{
for(;;){
boost::this_thread::sleep(boost::posix_time::milliseconds(SleepTime));
boost::mutex::scoped_lock lock(GraphItemMutex);
boost::this_thread::interruption_point() ;
updateData();
lock.unlock();
CastData();
GraphItemMutexConditionVariable.notify_one();
}
}
catch (boost::thread_interrupted)
{
// Thread end
}
}
};
#endif // _IGraphElementBase_h_
#include "IGraphElementBase.h"
#ifndef _IGraphElement_h_
#define _IGraphElement_h_
using namespace std ;
class IGraphElement : public IGraphElementBase{
// We should define prototype of functions that will be subscribers to our data
typedef void FuncCharPtr(char*, int) ;
public:
struct GetResultStructure
{
int length;
char* ptr;
};
// initGet sets up a pointer holding a copy of pointer of data we want to return on Get() call
void InitGet(char * pointerToUseInGetOperations, int pointerToUseInGetOperationsSize)
{
pointerToGet = pointerToUseInGetOperations;
pointerToGetSize = pointerToUseInGetOperationsSize;
}
// Function for adding subscribers functions
void Add(FuncCharPtr* f)
{
FuncVec.push_back(f);
}
// Returns pointer to copy of current graphItem processed data
GetResultStructure Get()
{
boost::mutex::scoped_lock lock(GraphItemMutex);
char * dataCopy = new char[pointerToGetSize];
memcpy (dataCopy,pointerToGet,pointerToGetSize);
lock.unlock();
GraphItemMutexConditionVariable.notify_one();
GetResultStructure result;
result.ptr = dataCopy;
result.length = pointerToGetSize;
return result;
}
void Clean()
{
GraphWorker.interrupt();
GraphWorker.join();
CleanAPI();
//delete[] pointerToGet;
//pointerToGet = 0;
}
// Cast data to subscribers and clean up given pointer
void CastData(){
for (size_t i = 0 ; i < FuncVec.size() ; i++){
char * dataCopy = new char[pointerToGetSize];
memcpy (dataCopy,pointerToGet,pointerToGetSize);
FuncVec[i] (dataCopy, pointerToGetSize) ;}
}
// Cast given data to subscribers and clean up given pointer
void CastData(char * data, int length){
for(size_t i = 0 ; i < FuncVec.size(); i++){
char* dataCopy = new char[length];
memcpy(dataCopy, data, length);
FuncVec[i](dataCopy, length);
}
}
private:
// Char pointer to hold a copy of pointer of data we want to return on Get() call
char* pointerToGet;
int pointerToGetSize;
// Vector to hold subscribed functions
vector<FuncCharPtr*> FuncVec ;
};
#endif // _IGraphElement_h_
So what is most intresting for me in that classes in short:
- typedef void FuncCharPtr(char*, int) ;
- vector<FuncCharPtr*> FuncVec ;
- functions like void CastData(char * data, int length)
It is really wary intresting for me if it is possile to somehow using templates make my classes work with costume structures. So Is it possible and how to do such thing?
Templates are a parameterization of a class. That is, instead of having a bunch of different classes such as
class myclass_int
{
int x;
}
class myclass_double
{
double x;
}
etc...
if you can see the pattern, the only thing different is the type used, SO, we will use an abstract type called a template as a sort of place holder,
class myclass_T
{
T x;
}
THIS CLASS IS NOT A SINGLE CLASS BUT A WHOLE COLLECTION. If we replace T with int we get the first class and T with double we get the second.
But when we instantiate myclass_T we must then specify what T actually is(is it in an int, double, etc..)?
so we will define this parameterized class as
template <typename T>
class myclass
{
T x;
}
And use T as it we already new what it really was.
That one class represents all the possible classes you could make up that had specific types used(I gave 2 instances at the start).
Templates simply make it easier to define such classes. There are a lot more to it than that but it is the foundation of why they are useful. The way to think of a templated class is not as a class but as a "Super class". That is, a class that has the ability to take on different representations.
It's not a difficult concept BUT if you don't have a lot of experience with oop you might not really see why they are useful and think they make things more complex. But once you end up having to write very many similar classes that all only differ by the types used then you'll see why they are so useful(they are actually quite powerful because they end up being able to do a lot more).