First off, I know the assignment operator cannot be defined in a class that has some subclasses. I understand it is because we don't want to make Subclass1 = Subclass2 possible.
But let's assume Class is an abstract class and Subclass is its... ya know. Then, is it feasible to do something like this?
Class* p = new Subclass;
Subclass s1;
*p = s1;
Actually, I tried implementing that in my code, but it didn't work :)
Could you please help?
My full code:
#include <cstdlib>
#include <iostream>
#include <typeinfo>
using namespace std;
class BadIndex{
int index;
public:
BadIndex(int i):index(i){}
int getIndex(){ return index; }
};
template <typename t>
class Wielomian{
public:
~Wielomian(){}
virtual int getDeg() = 0;
virtual t& operator [](int) = 0;
virtual bool operator ==(Wielomian<t>&) = 0;
virtual Wielomian<t>& operator +(Wielomian<t>&) = 0;
virtual Wielomian<t>& operator +=(Wielomian<t>&) = 0;
};
template <typename t>
class TabWiel: public Wielomian<t>{
int deg;
t* plnml;
public:
TabWiel(t tab[] = {}, int size = 0);
~TabWiel();
TabWiel(const TabWiel<t>&);
TabWiel<t>& operator =(const TabWiel<t>&);
template <typename st>
friend ostream& operator <<(ostream& s, TabWiel<st>& tw);
int getDeg(){ return deg; }
t& operator [](int);
bool operator ==(Wielomian<t>&);
TabWiel<t>& operator +(Wielomian<t>&);
TabWiel<t>& operator +=(Wielomian<t>&);
};
template <typename t>
TabWiel<t>& TabWiel<t>::operator =(const TabWiel<t>& tw){
if (this != &tw){
delete[] plnml;
deg = tw.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tw.plnml[i];
}
return *this;
}
template <typename t>
TabWiel<t>::TabWiel(t tab[], int size){
deg = size - 1;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tab[i];
if (deg == -1){
deg = 0;
plnml[0] = 0;
}
}
template <typename t>
TabWiel<t>::~TabWiel(){
delete[] plnml;
}
template <typename t>
TabWiel<t>::TabWiel(const TabWiel<t>& tw){
deg = tw.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tw.plnml[i];
}
template <typename t>
t& TabWiel<t>::operator [](int s){
if (s >= 0 && s < deg + 1)
return plnml[s];
else
throw BadIndex(s);
}
template <typename t>
bool TabWiel<t>::operator ==(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
if (deg == rhs.deg){
for (int i = 0; i < deg + 1; i++){
if (plnml[i] != rhs.plnml[i])
return false;
}
return true;
}
return false;
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
template <typename t>
ostream& operator <<(ostream& s, TabWiel<t>& tw){
for (int i = 0; i < tw.deg + 1; i++){
if (i != tw.deg)
s << tw.plnml[i] << "x^" << i << "+";
else
s << tw.plnml[i] << "x^" << i << endl;
}
return s;
}
template <typename t>
TabWiel<t>& TabWiel<t>::operator +(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
if (rhs.deg <= deg){
for (int i = 0; i < rhs.deg + 1; i++)
plnml[i] = plnml[i] + rhs.plnml[i];
return *this;
}
else{
t* tmp = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
tmp[i] = plnml[i];
int tmp_deg = deg;
delete[] plnml;
deg = rhs.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++){
if(i < tmp_deg + 1)
plnml[i] = tmp[i] + rhs.plnml[i];
else
plnml[i] = rhs.plnml[i];
}
return *this;
}
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
template <typename t>
TabWiel<t>& TabWiel<t>::operator +=(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
TabWiel<t>* nowy = new TabWiel<t>;
TabWiel<t> copy;
copy = *this;
*nowy = copy + rhs;
return *nowy;
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
I wish the assignment of *p to non-empty subclass object worked. But it doesn't - all the code does, is that it enters "Wielomian" definition and then proceeds to the next line of the main function (which in my case is the last line).
Your question is very interesting.
First of all, your code doesn't work because of slicing: you have two objects of Subclass, but
the compiler thinks that one of it is only a Class. So the code generated copies only the common
part of the data.
To demonstrate this, let's ellaborate on gha.st 's initial code extract:
struct Class { int a; virtual void hugo() = 0; };
struct Subclass : Class { int b; void hugo() override { cout<<"sub"<<a<<b<<endl; } };
int main() {
Class* p = new Subclass;
static_cast<Subclass*>(p)->a = 2;
static_cast<Subclass*>(p)->b = 3;
Subclass s1;
s1.a = 4; s1.b=5;
*p = s1; // slicing !!
p->hugo();
return 0;
}
What happens here ? Well, b member isn't copied, although *p is in reality a Subclass !
But *p is still a Subclass, so we could use polymorphism to get this work. The trick is to use an virtual clone() member to clone
an object (the object shall know its own type) into a target, if the target has the same type.
Then you could define operator=() for Class to use this clone(). This makes it handy to use, but the drawback is that you'll no longer
be able to rely on default operator= for any descendent of Class if you want to avoid an endless recursion.
Here the proof of concept:
struct Class {
int a;
virtual void hugo() = 0;
virtual bool clone(Class*t) = 0;
Class& operator=(Class& o) {
if (!o.clone(this)) { // try to clone on subclass on a target of same subclass
// here,the source and target might differ. Only common members can be copied
a = o.a;
}
return *this;
}
};
struct Subclass : Class {
int a,b;
void hugo() override { cout<<"sub"<<a<<b<<endl; }
bool clone(Class*t) {
cout<<"Clone ";
if (dynamic_cast<Subclass*>(t)) { // if source and target of same subclass
//*dynamic_cast<Subclass*>(t) = *this; // this doesn't work cause default operator will try to copy the Class base, causing recursion
dynamic_cast<Subclass*>(t)->a = a; // copy members
dynamic_cast<Subclass*>(t)->b = b;
return true;
}
else return false; // or tell that class of source and target are different.
}
};
Then you can use the main() function above, and see that the object is properly copied.
This trick is a kind of simplified double dispatch. You could even elaborate further by foreseing various kind of conversions depending on source and target subtype.
Related
The goal I set to myself is to overload operator+ (adding class objects). It turns out that this sum can be just interpreted as the sum of two vectors. But when it comes to the method operator+, I find it difficult to return the object. I've read similar topics and even try to apply some sugestions but with no success, unfortunatelly. I enclose some of my code.
template<class Y>
class myVect {
public:
myVect(int n = 1);
~myVect();
myVect(const myVect& a);
myVect& operator= (const myVect&);
myVect& operator+ (const myVect&);
void display(const myVect& a);
private:
int size;
Y* data;
template<class U> friend class myClass;
};
template<class Y> // constructor
myVect<Y>::myVect(int n) {
size = n;
data = new Y[size];
cout << endl << "Pass the elements" << " " << size << "\n";
for (int i = 0; i < size; i++) {
cin >> *(data + i);
}
}
template <class Y> // deconstructor
myVect<Y> :: ~myVect() {
delete[] data;
}
template<class Y> // copy constructor
myVect<Y> ::myVect(const myVect & a) {
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
template<class Y> //ASSIGMENT OPERATOR
myVect<Y> & myVect<Y> :: operator= (const myVect<Y> & a) {
if (this != &a) {
delete[] data;
size = a.size;
data = new Y[size];
for (int i = 0; i < size; i++) {
*(data + i) = *(a.data + i);
}
}
return *this;
}
The method operator+ is a follows:
template<class Y>
myVect<Y>& myVect<Y> ::operator+ (const myVect<Y>& a) {
if (this->size != a.size) {
cout << endl << "not able to perform that operation - wrong dimensions" << endl;
}
else {
myVect<Y> newObj(this->size);
for (int i = 0; i < this->size; i++) {
*(newObj.data + i) = *(this->data + i) + *(a.data + i);
}
}
return newObj;
}
The error I get is 'newObj': identifier not found. I believe it's due to deconstructor. I tried to put the class myVect into a new class (encapsulate it) and contruct the return method but it didn't change antything - the type of the error is still the same. Do you know how to solve this problem?
Anyway, if it is the destructor fault, does that mean that newObj is deleted before its return?
The problem can be reduced to this:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
}
return x;
}
The variable is scoped to the if block. It doesn't exist outside of it.
You'll have to move its declaration out of the conditional, and do whatever else is required to make that work… or return from inside the condition, and do something else (throw an exception?) otherwise.
For example, given the above demonstration:
int foo()
{
int x = 0; // Or some other value
if (true) // In reality, some meaningful condition
{
x = 4;
}
return x;
}
or:
int foo()
{
if (true) // In reality, some meaningful condition
{
int x = 4;
return x;
}
throw std::runtime_error("For some reason I have no value to give you!");
}
Your next problem will be that you are trying to return a local variable by reference. You cannot do that. Return it by value instead, which is anyway idiomatic for what you're doing.
You've declared your object inside of a block, so it won't exist in the outside scope. This would normally free you up to reuse variable names across different branches; try making a newObj inside the if part of the statement and watch it not throw an error, for example.
So I ran into this issue as I was coding for the class I'm currently in, I believe the code should run fine but this came up: Binary '[': no operator found which takes a left hand operand of type 'const SortableVector'
I'm not quite sure how to tackle this, any suggestions?
I ended up looking at No '==' operator found which takes a left-hand operand of const Type to see if I could find a solution in there however I did not, it seems my issue is stemming from something that I don't personally see.
#include <iostream>
#include "SortableVector.h"
using namespace std;
int main() {
const int SIZE = 10;
SortableVector<int> intTable(SIZE);
for (int x = 0; x < SIZE; x++) {
int z;
cout << "Please enter a number with no decimals: ";
cin >> z;
intTable[x] = z;
}
cout << "These values are in intTable:\n";
intTable.print();
intTable.sortInt(intTable, SIZE);
cout << "These values in intTable are now sorted: ";
intTable.print();
return 0;
}
//SortableVector.h
#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
using namespace std;
struct IndexOutOfRangeException {
const int index;
IndexOutOfRangeException(int ix) : index(ix) {}
};
template<class T>
class SortableVector {
unique_ptr<T[]> aptr;
int vectorSize;
public:
SortableVector(int);
SortableVector(const SortableVector &);
int size() const { return vectorSize; }
T &operator[](int);
void sortInt(SortableVector<int>, int);
void print() const;
};
template<class T>
SortableVector<T>::SortableVector(int s) {
vectorSize = s;
aptr = make_unique<T[]>(s);
for (int count = 0; count < vectorSize; count++) {
aptr[count] = T();
}
}
template<class T>
SortableVector<T>::SortableVector(const SortableVector &obj) {
vectorSize = obj.vectorSize;
aptr = make_unique<T[]>(obj.vectorSize);
for (int count = 0; count < vectorSize; count++) {
aptr[count] = obj[count];
}
}
template<class T>
T &SortableVector<T>::operator[](int sub) {
if (sub < 0 || sub >= vectorSize) {
throw IndexOutOfRangeException(sub);
return aptr[sub];
}
}
template<class T>
void SortableVector<T>::sortInt(SortableVector<int> x, int z) {
int i, j;
int temp = 0;
for (i = 0; i < z - 1; i++) {
for (j = 0; j < z - 1; j++) {
if (x[j] > x[j + 1]) {
temp = x[j];
x[j] = x[j + 1];
x[j + 1] = temp;
}
}
}
}
template<class T>
void SortableVector<T>::print() const {
for (int k = 0; k < vectorSize; k++) {
cout << aptr[k] << " ";
}
cout << endl;
}
Your operator[] returns a reference to the element, which will allow people to directly change the element. The problem happens when you try to use the operator on a const object (when you used const references to pass things to functions). This will allow someone to change the object through that reference returned by operator[], which breaks const-correctness and therefore is not allowed.
In case you're sill confused, let's say you have some class like this:
class Foo
{
private:
int numbers[100];
public:
int& operator[](const int & pos)
{
return numbers[pos];
}
};
This works fine for creating an object and using the bracket operator to access the elements. However, when you try to create a const object:
const Foo f;
You can do something like this:
f[3] = 5;
operator[] returns a reference, which can be used to directly change the data stored in f. f is declared as const though, so this must not happen and the compiler gives an error.
The solution would be to have two versions of operator[], overloaded by their const-ness:
class Foo
{
private:
int numbers[100];
public:
int& operator[](const int &pos)
{
return numbers[pos];
}
const int& operator[](const int &pos) const
{
return numbers[pos];
}
};
I'm a beginner when it comes to C++ and have recently ran in to a very frustrating problem with my small program where I'm practicing operator overloading and templates.
I've created a template-class called SortedVector that can store instances of various types.
using namespace std;
template <class T, int size> class SortedVector {
public:
SortedVector();
bool add(const T& v);
T& median();
void sortArray();
void removeLarge(const T& v);
void print(ostream &os);
void compexch(T& x, T& y);
void sortArray(T* data, int s);
private:
T arr[size];
int arraySize;
};
template <class T, int size> SortedVector<T, size>::SortedVector() {
arraySize = 0;
for (int i = 0; i < size; i++) {
arr[i] = T();
}
}
template <class T, int size> bool SortedVector<T, size>::add(const T& v) {
if (arraySize > size - 1) {
cout << "Array is full!" << endl;
return false;
} else {
arr[arraySize] = v;
arraySize++;
sortArray(arr, arraySize);
}
return true;
}
template <class T, int size> void SortedVector<T, size>::sortArray(T* data, int s) {
for (int i = 0; i < s - 1; i++) {
for (int j = i + 1; j < s; j++) {
compexch(data[i], data[j]);
}
}
}
template <class T, int size > T & SortedVector<T, size>::median() {
}
template <class T, int size> void SortedVector<T, size>::removeLarge(const T & v) {
}
template <class T, int size> void SortedVector<T, size>::print(ostream & os) {
for (int i = 0; i < arraySize; i++) {
cout << arr[i] << endl;
}
}
template <class T, int size> inline void SortedVector<T, size>::compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
It can store ints succesfully and it can also store Polygons (a custom made class created in a earlier assignment).
Polygon.h:
class Polygon {
public:
Polygon(Vertex vertexArray[], int size);
Polygon() : vertices(0), arraySize(0) {}
~Polygon() {delete[] vertices;}
void add(Vertex v);
float area();
int minx();
int maxx();
int miny();
int maxy();
int numVertices() const {return arraySize;}
friend ostream &operator << (ostream &output, const Polygon& polygon);
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
private:
int arraySize;
Vertex * vertices;
};
Polygon.cpp declaration:
using namespace std;
void Polygon::add(Vertex v) {
arraySize++;
Vertex * tempVertexes = new Vertex[arraySize];
for (int i = 0; i < arraySize; i++) {
if (i == arraySize - 1) {
tempVertexes[i] = v;
} else {
tempVertexes[i] = vertices[i];
}
}
delete [] vertices;
vertices = tempVertexes;
}
Polygon::Polygon(Vertex vertexArray[], int size) {
arraySize = size;
vertices = new Vertex[size];
for (int i = 0; i < size; i++) {
vertices[i] = vertexArray[i];
}
}
float Polygon::area() {
float area = 0.0f;
for (int i = 0; i < arraySize - 1; ++i) {
area += (vertices[i].getXposition() * vertices[i + 1].getYposition()) - (vertices[i + 1].getXposition() * vertices[i].getYposition());
}
area += (vertices[0].getYposition() * vertices[arraySize - 1].getXposition()) - (vertices[arraySize - 1].getYposition() * vertices[0].getXposition());
area = abs(area) *0.5;
return area;
}
ostream& operator<<(ostream &output, const Polygon& polygon) { //Kolla denna!
output << "{";
for (int i = 0; i < polygon.numVertices(); i++) {
output << "(" << polygon.vertices[i].getXposition() << "," << polygon.vertices[i].getYposition() << ")";
}
output << "}";
return output;
}
bool operator>(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() > polygon2.area()) {
return true;
} else {
return false;
}
}
bool operator<(Polygon polygon1, Polygon polygon2) {
if (polygon1.area() < polygon2.area()) {
return true;
} else {
return false;
}
}
template <class T> inline void compexch(T& x, T& y) {
if (y < x) {
T temp = x;
x = y;
y = temp;
}
}
The code for the Vertex class:
class Vertex {
public:
Vertex() : y(0), x(0) {}
Vertex(int xPosition, int yPosition) : x(xPosition), y(yPosition) {}
~Vertex() {}
int getXposition() const {return x;}
int getYposition() const {return y;}
private:
int x;
int y;
};
The problem however is that the overloaded <<-operator seems print out the wrong values from the main-method:
int main() {
SortedVector<Polygon, 10> polygons;
SortedVector<int, 6> ints;
ints.add(3);
ints.add(1);
ints.add(6);
Vertex varr[10];
varr[0] = Vertex(0, 0);
varr[1] = Vertex(10, 0);
varr[2] = Vertex(5, 2);
varr[3] = Vertex(5, 5);
polygons.add(Polygon(varr, 4));
cout << "varr area:" << (Polygon(varr, 4)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(25, 8);
varr[2] = Vertex(10, 23);
polygons.add(Polygon(varr, 3));
cout << "var area (1):" << (Polygon(varr, 3)).area() << endl;
varr[0] = Vertex(0, 0);
varr[1] = Vertex(5, 0);
varr[2] = Vertex(5, 3);
varr[3] = Vertex(4, 8);
varr[4] = Vertex(2, 10);
polygons.add(Polygon(varr, 5));
cout << "var area (2):" << (Polygon(varr, 5)).area() << endl;
polygons.print(cout);
ints.print(cout);
cout << "MEDIAN: " << ints.median() << endl;
cout << "MEDIAN: " << polygons.median() << endl;
return 0;
}
The code that is printed is:
var area (1):247.5
var area (2):33.5
{(6029504,0)(5,0)(5,3)}
{(6029504,0)(5,0)(5,3)(4,8)}
{(6029504,0)(5,0)(5,3)(4,8)(2,10)}
1
3
6
MEDIAN: 1
MEDIAN: {(6029504,0)(5,0)(5,3)}
Firstly, the method prints out the same polygon but with varying sizes. Secondly, it points out the wrong getXPosition() for the first object in the array. Everything else (that is implemented, like the ints and the area) is correct tho. Why is this? Am I missing something important here or am I just completely of with my program?
If theres any more code needed I am happy to provide it.
Regards
Given the code you posted, the issues are clear as to what's wrong.
You're passing Polygon's by value here:
friend bool operator > (Polygon polygon1, Polygon polygon2);
friend bool operator < (Polygon polygon1, Polygon polygon2);
and you're copying and assigning values here in: compexch:
if (y < x) {
T temp = x; // copy constructor
x = y; // assignment
y = temp; // assigment
}
This means that copies will be made, and your Polygon class cannot be copied safely. You will have memory leaks and bugs when calling either of these functions.
You should implement the appropriate copy constructor and assignment operator, whose signatures are:
Polygon(const Polygon& rhs); // copy constructor
Polygon& operator=(const Polygon& rhs); // assignment operator
Both of these functions should be implemented. Please see the Rule of 3 for this information.
However, for operator < and operator >, you should pass references, not values to these functions:
friend bool operator > (Polygon& polygon1, Polygon& polygon2);
friend bool operator < (Polygon& polygon1, Polygon& polygon2);
Then the copy constructor and assignment operator are not brought into play, since the parameter type is a reference.
Let's try to implement the copy / assignment functions anyway, for completeness:
For example, the copy constructor can be implemented like this:
Polygon::Polygon(const Polygon& rhs) : vertices(new int[rhs.arraySize]),
arraySize(rhs.arraySize)
{
for (int i = 0; i < arraySize; ++i)
vertices[i] = rhs.vertices[i];
}
Then for the assignment operator, using the copy / swap idiom:
Polygon& operator=(const Polygon& rhs)
{
Polygon temp(rhs);
std::swap(temp.arraySize, arraySize);
std::swap(temp.vertices, vertices);
return *this;
}
Once you've implemented these function, plus the destructor that calls delete[], you should no longer have an issue with copying the objects.
Other issues:
In addition, you really should only overload < and ==, initially with their "full" implementation, and write the other relational operators with respect to these two operators.
Right now, you're making the classic mistake of writing one operator (operator >), and then trying to turn the logic "inside-out" when implementing operator <. What if the logic for operator > were more complex, and it took yeoman's work to figure out what is the "opposite of <"?
If you implemented ==, then operator > just becomes:
return !(polygon1 < polygon2) && !(polygon == polygon2); // <-- this can be further improved by implementing operator !=
After really hard search for answers...
I tried fo(u)r hours to get and set values to an array with Overloading the subscript operator “[ ]” but can't figure out why it won't work.
What I'm tring to do here is to set someType value to an array member (On Main "darr1[i] = i*10.0" for example) with overloading the [] and with overloading the = and to get someType value from an array member (On Main "<< darr1[i] << endl" for example) but can't figure out why just the overloading of: "Type & operator [] (int index)" is invoking.
My program doesn't get to the '=' overloading or to the second '[]' overloading at all..
here is my program (sorry for the long one):
#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
class AO1Array
{
private:
int _size;
protected:
int top;
int *B;
int *C;
AO1Array(int n);
~AO1Array();
bool isRealValue(int index)
{
if ((0 <= B[index] && B[index] < top) && (index == C[B[index]]))
return true;
return false;
};
};
AO1Array::AO1Array(int n)
{
_size = n;
top = 0;
B = new int[n];
C = new int[n];
}
AO1Array::~AO1Array()
{
delete[] B;
B = NULL;
delete[] C;
C = NULL;
}
template<class Type>
class GenericO1Array : AO1Array
{
public:
GenericO1Array(int size, Type initVal) : AO1Array(size)
{
_initVal = initVal;
Len = size;
A = new Type[size];
}
~GenericO1Array()
{
delete[] A;
A = NULL;
}
int Length() { return Len; }
Type & operator [](int index) const
{
if (AO1Array::isRealValue(index))
return A[index];
return _initVal;
}
Type & operator [] (int index)
{
if (AO1Array::isRealValue(index))
realValue = true;
else
realValue = false;
return A[index];
}
Type operator =(Type value)
{
if (realValue)
A[lastIndex] = _initVal;
else
{
AO1Array::C[top] = lastIndex;
AO1Array::B[lastIndex] = AO1Array::top++;
A[index] = value;
}
return *this;
}
private:
int Len;
int lastIndex;
bool realValue;
Type _initVal;
Type *A;
};
int main()
{
int n = 20;
GenericO1Array<double> darr1(n, 1.1);
GenericO1Array<long> iarr1(n, 2);
int i;
cout << "\nLength.darr1 = " << darr1.Length() << endl;
cout << "\nLength.iarr1 = " << iarr1.Length() << endl;
for (i = 0; i < n; i += 2)
{
darr1[i] = i*10.0;
iarr1[i] = i * 100;
} // for
cout << "\ndarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "darr1[" << i << "] = " << darr1[i] << endl;
cout << "\niarr1 = " << endl;
for (i = 0; i < n; i++)
cout << "iarr1[" << i << "] = " << iarr1[i] << endl;
} // main
My program doesn't get to the '=' overloading
You are overloading the = assignment operator of Generic01Array itself, but nothing in your code is actually assigning values to your darr1 or iarr1 variables directly (there are no darr1 = ... or iarr = ... statements). That is why your = operator is not being invoked.
If you want something to happen when the user assigns a value to an element of your array, you need to create a proxy class and overload its = assignment operator, then have your [] operator return an instance of that proxy:
template<class Type>
class GenericO1Array : AO1Array
{
public:
class Proxy;
friend Proxy;
class Proxy
{
private:
Generic01Array& _arr;
int _index;
public:
Proxy(Generic01Array &arr, int index) : _arr(arr), _index(index) {}
operator Type() const
{
if (_arr.isRealValue(index))
_arr.realValue = true;
else
_arr.realValue = false;
return _arr.A[_index];
}
Proxy& operator=(const Type &value)
{
if (_arr.realValue)
_arr.A[_arr.lastindex] = _arr._initVal;
else
{
_arr.C[_arr.top] = _arr.lastIndex;
_arr.B[_arr.lastIndex] = _arr.top++;
_arr.A[_index] = value;
}
return *this;
}
};
...
Proxy operator [] (int index)
{
return Proxy(*this, index);
}
...
};
or to the second '[]' overloading at all..
You have two overloads of the [] operator, one that is const and the other is not. The const version of [] is breaking the const-ness of the operator by returning a non-const reference to the array's internal data. It should be returning a non-reference const value instead:
const Type operator [](int index) const
The non-const version of the [] operator can return a reference:
Type& operator [](int index)
You are not calling the [] operator on any const instances of your Generic01Array class, so only the non-const version of your [] operator should be getting invoked.
Can someone tell me if this is correct. I'm trying to overload my << operator for an array in my dynamic array class below.
Specefically,
Can I put std:ostream in the class itself? This does not seem corrrect. Compiler error is telling me it should only take one argument.
void print_array(std::ostream &os = cout)
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
std::ostream& operator<<(std::ostream& stream, dynamic_array const& data)
{
data.print_array(stream);
return stream;
}
Dynamic Array Class
/*
Needs a reszie function added
Merge sort is better for sequential, stable(equal elements not re-arranged, or
*/
#include "c_arclib.cpp"
template <class T> class dynamic_array
{
private:
T* array;
T* scratch;
void merge_recurse(int left, int right)
{
if(right == left + 1)
{
return;
}
else
{
int i = 0;
int length = right - left;
int midpoint_distance = length/2;
int l = left, r = left + midpoint_distance;
merge_recurse(left, left + midpoint_distance);
merge_recurse(left + midpoint_distance, right);
for(i = 0; i < length; i++)
{
if((l < (left + midpoint_distance)) && (r == right || array[l] > array[r]))
{
scratch[i] = array[l];
l++;
}
else
{
scratch[i] = array[r];
r++;
}
}
for(i = left; i < right; i++)
{
array[i] = scratch[i - left];
}
}
}
void quick_recurse(int left, int right)
{
int l = left, r = right, tmp;
int pivot = array[(left + right) / 2];
while (l <= r)
{
while (array[l] < pivot)l++;
while (array[r] > pivot)r--;
if (l <= r)
{
tmp = array[l];
array[l] = array[r];
array[r] = tmp;
l++;
r--;
}
}
if (left < r)quick_recurse(left, r);
if (l < right)quick_recurse(l, right);
}
public:
int size;
dynamic_array(int sizein)
{
size=sizein;
array = new T[size]();
}
void print_array(std::ostream &os = cout)
{
for (int i = 0; i < size; i++) os << array[i] << endl;
}
std::ostream& operator<<(std::ostream& stream, dynamic_array const& data)
{
data.print_array(stream);
return stream;
}
void print_array()
{
for (int i = 0; i < size; i++) cout << array[i] << endl;
}
int merge_sort()
{
scratch = new T[size]();
if(scratch != NULL)
{
merge_recurse(0, size);
return 1;
}
else
{
return 0;
}
}
void quick_sort()
{
quick_recurse(0,size);
}
void rand_to_array()
{
srand(time(NULL));
int* k;
for (k = array; k != array + size; ++k)
{
*k=rand();
}
}
void order_to_array()
{
int* k;
int i = 0;
for (k = array; k != array + size; ++k)
{
*k=i;
++i;
}
}
void rorder_to_array()
{
int* k;
int i = size;
for (k = array; k != array + size; ++k)
{
*k=i;
--i;
}
}
};
int main()
{
dynamic_array<int> d1(1000000);
d1.order_to_array();
clock_t time_start=clock();
d1.merge_sort();
clock_t time_end=clock();
double result = (double)(time_end - time_start) / CLOCKS_PER_SEC;
cout << result;
}
Put the operator outside of your class:
template <class T> class dynamic_array
{
...
// if you need to use protected/private members:
friend std::ostream& operator<<(std::ostream& stream,
dynamic_array<T> const& data);
}
template <class T>
std::ostream& operator<<(std::ostream& stream, dynamic_array<T> const& data)
{
data.print_array(stream);
return stream;
}
Since the left operand of the operator<< will be the ostream, not the dynamic array object, you need to implement operator<< as a global function, not a member function (a member function overload is always invoked as object.operator<<(argument), so the object of which it's a member must be the left operand.
If that needs access to the internals of the object, you can make it a friend. If (as in this case) it uses only the public interface of the object (print_array, in your case), then it can just be a normal global function.
template <class T>
class dynamic_array {
// ...
};
template <class T>
std::ostream &operator<<(std::ostream &os, dynamic_array<T> const &a) {
a.print_array(os);
return os;
}
Personally, however, I'd probably make print_array a private member, and make the global operator<< a friend. This reduces the public interface of the class a bit (i.e., only one way to print a dynamic_array instead of two) with no loss of functionality (since the do precisely the same thing).