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.
Related
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 am practicing using templates and classes in C++. My goal is to write a template class for a deque. It will have functions to "insert_head", "insert_tail", "remove_tail", and "remove head", along with the ability to be printed using "cout". Also, the '=' operator must be able to be used to copy one instance of the class to another instance. Here is my current code:
#ifndef DEQUE_H
#define DEQUE_H
template <typename T>
class Deque {
public:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity)
{}
Deque(Deque & d) : x_(d.x()), size_(d.size()), capacity_(d.capacity()) {}
std::ostream & operator<<(std::ostream & cout) {
cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
cout << *(x_ + (size_ - 1)* sizeof(T));
}
cout << ']';
return cout;
}
Deque operator=(Deque d) {
Deque dq(d);
return dq;
}
void print_test() {
std::cout << '[';
if (size_ > 0) {
for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
std::cout << *(x_ + i) << ',';
}
std::cout << *(x_ + (size_ - 1)* sizeof(T));
}
std::cout << ']';
}
int * x() {
return x_;
}
int size() {
return size_;
}
int capacity() {
return capacity_;
}
bool is_empty() {
return size_ == 0;
}
void insert_tail(T tail) {
if (size_ < capacity_) {
*(x_ + sizeof(T) * size_) = tail;
size_++;
} else {
// throw overflow
}
}
T remove_tail() {
if (size_ > 0) {
T ret = *(x_ + sizeof(T) * (size_ - 1));
std::cout << ret;
size_--;
return ret;
} else {
// throw underflow
}
}
void insert_head(T head) {
if (size_ > 0 && size_ < capacity_) {
for (int i = (size_ - 1) * sizeof(T); i < 0; i -= sizeof(T)) {
*(x_ + i + sizeof(T)) = *(x_ + i);
}
}
if (size_ < capacity_) {
*x_ = head;
size_++;
} else {
// throw overflow
}
}
T remove_head() {
if (size_ > 0) {
T ret = *x_;
for (int i = sizeof(T); i < size_* sizeof(T); i += sizeof(T)) {
*(x_ + i - sizeof(T)) = *(x_ + i);
}
size_--;
return ret;
} else {
// throw underflow
}
}
private:
T * x_;
int size_;
int capacity_;
};
#endif
Here is my test code using that class:
#include <iostream>
#include "Deque.h"
int main(int argc, char const *argv[])
{
Deque< int > dq;
dq.insert_head(1);
// dq.insert_head(2); // adding head when not empty causes bug
dq.insert_tail(3);
dq.insert_tail(4);
dq.insert_tail(5);
dq.print_test(); std::cout << std::endl;
// std::cout << dq; // '<<' not overloaded properly'
std::cout << dq.remove_head() << " head removed\n";
// int x = dq.remove_head(); // seg faults when assigning returned value to a variable
dq.insert_tail(2);
dq.print_test();
std::cout << std::endl;
Deque< int > dq1(dq);
Deque< int > dq2;
// dq2 = dq1; // '=' not overloaded properly
return 0;
}
Each of my four problems is in a commented out line of code in my test file, here is a further explaination:
When "dq.insert_head(2)" is called and dq is not empty (size > 0) I try to shift all the other elements in the deque over one position so I can insert the new value there, there is a problem and the elements are not moved over.
"std::cout << dq" does not print dq like it should. The code is very similar to the "print_test()" method, however when I run the program I get the error "no match for operator <<". Is this because it is template class? Or am I doing something else completely wrong?
When trying to remove the head or tail from the deque, I am trying to return the value removed. In the line of code not commented out, the returned value is printed as it should, but the following line of code causes a seg fault. Is it because I'm trying to assign a template varabale to an integer variable?
My last issue is the '=' operator is not copying one instance of the class to another. My goal was to create a new instance of the class then return that instance (as you can see in the "Deque operator=(Deque d)") but that is not working as I hoped. What is the best way to overload the '=' function using template classes.
Thank you for your help, the answer to any of these questions is much appreciated.
All of your functions have issues:
Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity) {}
If you allows to specify a size, then you would have to allocate and initialize memory for those items. You should only specify capacity.
x_ is not initialized.
Assuming, you want a fixed capacity, then your constructor should be:
Deque(int capacity = 1000)
: size_(0)
, x_(new T[capacity])
, capacity_(capacity)
{
}
And even that is a simplified version as it would call the constructor for all items which might be inefficient and require that T has an accessible default constructor.
And now for the copy constructor:
The copy constructor should do deep copy. Otherwise, your program will (probably) crash after deleting the first Deque for which you have done copies as deleting an item twice is undefined behavior.
The prototype should take a constant reference as in: Deque(const Deque &other);
The code would look similar to this:
Deque(const Deque &other)
: capacity_(other.capacity_)
, x_(new T[other.capacity_])
, size_(other.size_)
{
for (int i = 0; i != size_; ++i)
{
x_[i] = other.x_[i];
}
}
For the <<, the prototype should be:
friend std::ostream & operator<<(std::ostream &cout, const T &data)
assuming it is declared inside the class to access private fields. You need to pass the data on which the operator works.
For the assignment operator, something like this could works:
Deque& operator=(const Deque &other)
{
// Use swap idiom...
Deque tmp(other);
// Swap pointers so old x_ get destroyed...
T *old_x = x_;
x_ = tmp.x_;
tmp.x_ = old_x;
// Usually one would use std::swap.
// Here as tmp get destroyed, it is not strictly to swap capacity_ and size_.
capacity_ = tmp.capacity_;
size_ = tmp.size_;
}
Now for the x() function:
- If you do a queue, you probably don't want to expose data so the function should be removed.
- If it was kept, the function should be const and returns a pointer to T: T *x() const; for the expected functionality.
size, capacity and is_empty should all be const member functions.
insert_tail and remove_tail problems have been explain in other people comments (in particular extraneous sizeof).
Similar problems for insert_head and remove_head also. In addition, the code that copy existing items could be refactored inside a private function to follows the DRY principle and avoid code duplication.
The answer to your first problem is to remove the sizeof(T) so you end up with this
for (int i = (size_ - 1); i > 0; i --) {
*(x_ + i + 1) = *(x_ + i);
}
The answer to your second problem is to change your declaration for your << overload to friend std::ostream & operator<<(std::ostream & x, Deque n) and initialize the body outside the class.
The answer to the third problem is that you can't return an int pointer which may point to a different block of memory location that what T could be.
The answer to the fourth question is to do the following:
Deque& operator=(const Deque& d) {
x_ = d.x_; // Deep copy
size_ = d.size_;
capacity_ = d.capacity_;
return *this;
}
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 !=
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.
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.