I'm learning about overloading and I've got curious if i could make an overloaded operator with two non-class arguments.
For example with vector class having x and y to call
vector += (4.5, -2.1);
Thank you!
EDIT
I've managed to do that, and also expanded to take as many arguments as user create. This is how it looks like:
//Point.hpp
class Point
{
friend class Proxy;
private:
double *val;
int i;
int amount;
public:
Point();
Point(const int&);
void Set(const int &);
double Get(const int &);
int Amount();
Proxy operator += (const double &add);
};
class Proxy
{
private:
int &i;
Point &temp_point;
public:
Proxy operator , (const double&);
Proxy(Point2D &, int&);
};
//Point.cpp
Point::Point()
{
this->amount = 2;
val = new double[this->amount];
val[0] = 0;
val[1] = 0;
};
Point::Point(const int &amount) : amount(amount)
{
val = new double[amount];
for (int i = 0; i < amount; i++)
{
val[i] = 0;
}
};
void Point::Set(const int &nr)
{
do
{
std::cout << "Give me value of " << nr << " coordinate: ";
std::cin.clear();
std::cin.sync();
std::cin >> val[nr];
if (std::cin.fail())
{
std::cout << "Try again, not acceptable...\n";
}
} while (std::cin.fail());
}
double Point::Get(const int &nr)
{
return val[nr];
}
int Point::Amount()
{
return this->amount;
}
Proxy Point::operator += (const double &add)
{
this->i = 0;
this->val[i++] += add;
return Proxy(*this, i);
}
Proxy::Proxy(Point &point, int &i) : temp_point(point), i(i)
{}
Proxy Proxy::operator , (const double &value)
{
temp_point.val[i++] += value;
return Proxy(temp_point, i);
}
//Source.cpp example
int main()
{
Point example(3);
example += 4.5, -2.3, 3.0;
for (int i = 0; i < example.Amount(); i++)
{
std::cout << example.Get(i) << " ";
}
std::cout << std::endl;
system("PAUSE");
return 0;
}
Hope somebody find it useful.
This won't work, because (4.5, -2.1) will invoke the built-in comma operator, and simply evaluate to -2.1. It would be possible to do this:
vector += 4.5, -2.1;
This works because , has lower precedence than +=. You can overload += so that it returns a proxy object, which in turn has an overloaded , operator that will append additional elements.
You could use an std::initializer_list
v & operator += (std::initializer_list<int> l)
{
sum = std::accumulate(l.begin(), l.end(), sum);
.....
You'll have to sligthly change your call to
vector += {1 , 2};
If you have a vector of pairs, a much more readable option would be to
vector += std::make_pair( 4.5, -2.1 );
Looks less magical, which usually a good thing.
Related
This is part of my polynomial.cpp to get terms by overloading istream
void Newterm(float coef, int deg) {
if (terms == capacity) {
capacity *= 2;
Term* tmp = new Term[capacity];
copy(termArray, termArray + terms, tmp);
termArray = tmp;
delete[] tmp;
}
termArray[terms].degree = deg;
termArray[terms++].coef = coef;
}
friend istream& operator >> (istream& is, Polynomial& pl) {
cout << "number of terms : ";
int t; is >> t;
cout << endl;
float coeff;
int degree;
for (int i = 0; i < t;i++) {
cout << i + 1 << "'s term: ";
is >> coeff >> degree;
pl.Newterm(coeff, degree);
}
return is;
};
of course, i tried to figure out whaaat made this result..
tried:
removing 'for' loop
this actually worked.. but it only works when terms=1
firstly creating term and input data
Newterm(0,0);
is>>pl.termArray[i].coef>>pl.termArray[i].degree;
it couldn't fix anything...
so i think it has to do with loops..
but whyyyy?
Using std::vector instead of doing your own memory managment
(why reinvent the wheel if there is a tested solution in the standard library)
#include <iostream>
#include <vector>
struct Term final
{
Term() = default;
~Term() = default;
Term(int d, double c) :
degree{ d },
coef{ c }
{
}
int degree{ 0 };
double coef{ 1.0 };
};
class Polynomial final
{
public:
Polynomial() = default;
~Polynomial() = default;
explicit Polynomial(const std::initializer_list<Term> terms) :
m_terms{ terms }
{
}
void add(const Term& term)
{
m_terms.push_back(term);
}
private:
std::vector<Term> m_terms;
};
std::istream& operator>>(std::istream& is, Polynomial& polynomial)
{
std::size_t n{ 0 }; // indices are not ints the can't be < 0
is >> n;
for (std::size_t i = 0; i < n; ++i)
{
Term term{};
is >> term.coef;
is >> term.degree;
polynomial.add(term);
}
return is;
}
int main()
{
// to show you that std::vector can handle all the memory managment for you
// constructor with an initializer list that adds 3 terms
// that's also why the Term has a constructor, it is to make it work with
// initializer list
Polynomial p{ { 1,2.0 }, { 2,4.0 }, { 1,-1.0 } };
}
I keep getting this error that only virtual functions can be marked as override but the functions in question "norm()" and "string to_string()" are virtual. what could be causing this?
In my main function I am also getting the error no matching member function to call push back, did I make a mistake along the way somewhere and I am just not seeing it?
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
class Group
{
public:
virtual string to_string() = 0;
virtual int norm() = 0;
};
class Real
{
// add your code here
protected:
int number;
public:
Real(int num)
{
number = num;
}
int norm() override
{
return number;
}
string to_string() override
{
return number;
}
int getNumber() const
{
return number;
}
void setNumber(int number)
{
Real::number = number;
}
};
class Complex : public Real
{
// add your code here
protected:
int imaginary;
public:
Complex(int realNum, int imag) : Real(realNum)
{}
int norm() override
{
return sqrt(number * number + imaginary * imaginary) + 'i';
}
string to_string() override
{
return ::to_string(number) + '+' + ::to_string(imaginary) + 'i';
}
};
class Trinomial : public Complex
{
// add your code here
protected:
int third;
public:
Trinomial(int p1, int p2, int p3) : Complex(p1, p2) {
third = p3;
}
int norm() override {
return sqrt(number * number + imaginary * imaginary + third * third);
}
string to_string() override {
return ::to_string(number) + "x^2+" + ::to_string(imaginary) + "x+" + ::to_string(third);
}
};
class Vector : public Group
{
// add your code here
protected:
vector<int> v;
public:
Vector(int num1, int num2, int num3)
{
v.push_back(num1);
v.push_back(num2);
v.push_back(num3);
}
int norm() override
{
int squared_sum = 0;
for (int i = 0; i < v.size(); i++) {
squared_sum += v[i] * v[i];
}
return sqrt(squared_sum);
}
string to_string() override
{
string str = "[";
for (int i = 0; i < v.size() - 1; i++) {
str += ::to_string(v[i]) + " ";
}
str += ::to_string(v[v.size() - 1]) + "]";
return str;
}
};
int main()
{
vector<Group*> elements;
elements.push_back(new Real{ 3 });
elements.push_back(new Complex{ 3,4 });
elements.push_back(new Trinomial{ 1,2,3 });
elements.push_back(new Vector{ 1,2,3 });
for (auto e : elements)
{
cout << "|" << e->to_string() << "| = " << e->norm() << endl;
}
for (auto e : elements)
delete e;
return 0;
}
A couple of issues here:
The class Real must have inherited from Group so that you could override the functions. That is the reason for the error message.
Secondly the Real::to_string must return a string at the end. You
might convert the integer using std::to_string.
Last but not least the Group must have a virtual destructor for defined behaviour. Read more here: When to use virtual destructors?
In short, you need
#include <string>
class Group
{
public:
// other code
virtual ~Group() = default;
};
class Real: public Group // --> inherited from base
{
// other codes
public:
std::string to_string() override {
return std::to_string(number);
}
};
As a side, please do not practice with using namespace std;
your class real has no parent. so you cant override to_string()
I have a class and i keep getting some error from the destructor.
This is the clas:
#pragma once
class Number
{
int bas;
char* val;
public:
Number(const char* value, int base);
Number(const Number& x);
~Number();
void SwitchBase(int newBase);
void Print();
int GetDigitsCount();
int GetBase();
};
This is the cpp file:
#include "Number.h"
#include <iostream>
Number::Number(const char* value, int base)
{
int a = -1;
do
{
a++;
} while (value[a] != '\0');
val = new char[a + 1];
for (int i = 0; i <= a; i++)
val[i] = value[i];
bas = base;
}
Number::Number(const Number& x)
{
int a = -1;
bas = x.bas;
do
{
a++;
} while (x.val[a] != '\0');
delete[]val;
val = new char[a + 1];
int i;
for (i = 0; i <= a; i++)
val[i] = x.val[i];
}
Number::~Number()
{
delete[]val;
}
void Number::Print()
{
std::cout << "Numarul este: " << val<< std::endl << "Baza este: " << bas<<std::endl;
}
int Number:: GetDigitsCount()
{
int l = 0;
do
{
l++;
} while (val[l] != '\0');
return l;
}
This is the main:
int main()
{
Number x("123", 10),y("111",10),z("0",10);
z = y;
z.Print();
}
I keep getting this error:
Invalid address specified to RtlValidateHeap( 010C0000, 010C8DD8 )
If i do this change in main it works properly but it is not really what I want...
int main()
{
Number x("123", 10),y("111",10);
Number z = y;
z.Print();
}
How can I solve this? I can't figure it out...
Your Number class is missing an assignment operator. Since you use the assignment operator in main the default assignment operator will cause a double delete when you exit main and this explains the error.
It also explains why the error goes away when you change main to use the copy constructor instead of the assignment operator.
You should look at the copy and swap idiom to show how to easily and efficiently implement copy constructors and assignment operators.
Alternatively you could also use std::string instead of manually allocating memory. This would eliminate the need to write a destructor, copy constructor and assignment operator. That's the best solution.
This is an example of how code may look like using std::string:
#include <iostream>
#include <string>
class Number
{
int bas;
std::string val;
public:
Number(std::string, int base);
Number(const Number& number);
Number& operator= (const Number& number);
~Number()=default;
void Print();
int GetDigitsCount();
};
Number::Number(std::string value, int base)
{
val=value;
bas=base;
}
Number::Number(const Number& number)
{
val=number.val;
bas=number.bas;
}
Number& Number::operator= (const Number& number)
{
val=number.val;
bas=number.bas;
return *this;
}
void Number::Print()
{
std::cout << "Numarul este: " << val<< std::endl << "Baza este: " << bas<<std::endl;
}
int Number:: GetDigitsCount()
{
return val.size();
}
int main()
{
Number x("123", 10),y("111",10),z("0",10);
Number k(y);
k.Print();
}
Say I have a simple vector class, vec:
#include <iostream>
#include <stdlib.h>
class vec {
public:
vec() {}
// Constructor.
vec(int n) {
len = n;
data = new double[len];
}
// Destructor.
~vec() { delete [] data; }
// Accessor.
double & operator[](int i) const {
check_index(i);
return data[i];
}
// Other methods...
// ....
protected:
int len;
double * data;
void check_index(int i) const {
if(i < 0 || i >= len) {
std::cerr << "Bad access.\n";
exit(1);
}
}
};
Now suppose I have a special type of vector with sparse structure, e.g., where every even-index is zero. Call this oddvec. Instances of oddvec should be declared just as with the vec class, but underneath, the memory use should be efficient since only half the data is non-zero.
The accessor for the oddvec class should return 0 if the index is even, and return the odd-index element (stored sequentially) otherwise. There a couple problems with this:
The double & return type is violated if the index is even, since the constant value, 0, is returned.
It's not clear to me how to handle the situation when an even index element is used as an lvalue. E.g., v[0] = 3.0 should not be allowed in the oddvec class, but is perfectly acceptable in the vector class. We can't simply throw an error when even indexes are used, because even indexes are fine as long as the intention is as an rvalue.
How do I design the accessor function for the oddvec class, while both keeping the memory storage efficient and inheriting all the methods from the parent?
Non-working example of oddvec:
class oddvec : public vec {
public:
// Constructor.
oddvec(int n) {
len = n;
data = new double[len/2];
}
// Accessor (doesn't work!)
double & operator[](int i) const {
check_index(i);
if (i%2 == 0)
return 0;
else
return data[(i-1)/2];
}
};
Upon compilation:
main.cpp: In member function ‘double& oddvec::operator[](int) const’:
main.cpp:49:20: error: invalid initialization of non-const reference of type ‘double&’ from an rvalue of type ‘double’
return 0;
Working example using proxy classes:
I have implemented a proxy class as suggested in the answer below.
proxies.h
#ifndef PROXIES_H
#define PROXIES_H
#include <iostream>
#include <stdlib.h>
class proxy {
public:
proxy(int i, double v, double * d) {
index = i;
value = v;
data = d;
}
void operator=(double rhs) {
data[index] = rhs;
}
friend std::ostream & operator<<(std::ostream & outs, const proxy & p) {
outs << p.value;
return outs;
}
protected:
int index;
double value;
double * data;
};
class oddproxy : public proxy {
public:
oddproxy(int i, int v, double * d) : proxy(i, v, d) {}
void operator=(double rhs) {
if (index%2 == 0) {
std::cerr << "Even entries of oddvec are not assignable.\n";
exit(1);
}
data[index/2] = rhs;
}
};
#endif
vectors.h
#ifndef VECTORS_H
#define VECTORS_H
#include "proxies.h"
class vec {
public:
vec() {}
// Constructor.
vec(int n) {
len = n;
data = new double[len];
}
// Destructor.
~vec() { delete [] data; }
// Accessor.
proxy operator[](int i) const {
check_index(i);
return proxy(i, data[i], data);
}
inline int length() const { return len; }
// Other methods...
// ....
protected:
int len;
double * data;
void check_index(int i) const {
if(i < 0 || i >= len) {
std::cerr << "Bad access.\n";
exit(1);
}
}
};
class oddvec : public vec {
public:
// Constructor.
oddvec(int n) {
len = n;
data = new double[len/2];
}
// Accessor.
oddproxy operator[](int i) const {
check_index(i);
return oddproxy(i, (i%2 == 0) ? 0 : data[i/2], data);
}
};
#endif
main.cpp
#include <iostream>
#include "vectors.h"
int main () {
int N = 5;
vec V(N);
oddvec O(N);
for(int i=0; i < V.length(); i++) {
V[i] = i;
if(i%2 != 0) {
O[i] = i;
}
}
for(int i=0; i < O.length(); i++) {
std::cout << "V[" << i << "]=" << V[i] << ", "
<< "O[" << i << "]=" << O[i] << "\n";
}
O[0] = 13;
return 0;
}
output
V[0]=0, O[0]=0
V[1]=1, O[1]=1
V[2]=2, O[2]=0
V[3]=3, O[3]=3
V[4]=4, O[4]=0
Even entries of oddvec are not assignable.
You can use proxy object to do this.
simple sample code:
#include <iostream>
#include <vector>
using namespace std;
class very_odd_vector{
public:
class only_odd_proxy;
friend class only_odd_proxy;
only_odd_proxy operator [](int index);
int operator [](int index)const{return index%2==0?0:content[index/2];}
unsigned int size()const{return content.size()*2;}
private:
vector<int> content{1,3,5,7,9};
};
class very_odd_vector::only_odd_proxy{
public:
only_odd_proxy(very_odd_vector& vec,int index):vec(vec),index(index){}
operator int(){return index%2==0 ? 0 : vec.content[index/2];}
only_odd_proxy& operator =(int value){
if(index%2==0)
cout << "BAD OPERATION";//any error you want
else
vec.content[index/2] = value;
return *this;
}
private:
very_odd_vector& vec;
int index;
};
auto very_odd_vector::operator [](int index)->only_odd_proxy{return only_odd_proxy(*this,index);}
int main(){
very_odd_vector v;
cout << "reading value\n";
for(int i=0;i<v.size();++i)
cout << v[i] <<'\n';
cout << "writting value\n";
for(int i=0;i<v.size();++i){
cout << i << ':';
v[i]=10;
cout << '\n';
}
cout << "reading value\n";
for(int i=0;i<v.size();++i)
cout << v[i] <<'\n';
}
Edit for updated part of question :
I think this class will fit your need more.
//Both base and inherit class return this class
class maybe_readonly_proxy {
public:
maybe_readonly_proxy(double* data, bool readonly):readonly(readonly),data(data){}
maybe_readonly_proxy& operator=(double rhs) {
if(readonly){/*whatever error*/}
else {*data = rhs;}
return *this;
}
operator double()const{return *data;}
private:
bool readonly;
double * data;
};
You may need a variable to contain readonly (0 in this case) value, or modify the operator double() the check readonly state
Or just implement get and set method separately and do not use this proxy may be another choice.
I'd like advice on a way to cache a computation that is shared by two derived classes. As an illustration, I have two types of normalized vectors L1 and L2, which each define their own normalization constant (note: against good practice I'm inheriting from std::vector here as a quick illustration-- believe it or not, my real problem is not about L1 and L2 vectors!):
#include <vector>
#include <iostream>
#include <iterator>
#include <math.h>
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) { }
double get_value(int i) const {
return (*this)[i] / get_normalization_constant();
}
virtual double get_normalization_constant() const = 0;
};
struct L1Vector : public NormalizedVector {
L1Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { }
double get_normalization_constant() const {
double tot = 0.0;
for (int k=0; k<size(); ++k)
tot += (*this)[k];
return tot;
}
};
struct L2Vector : public NormalizedVector {
L2Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { }
double get_normalization_constant() const {
double tot = 0.0;
for (int k=0; k<size(); ++k) {
double val = (*this)[k];
tot += val * val;
}
return sqrt(tot);
}
};
int main() {
L1Vector vec{0.25, 0.5, 1.0};
std::cout << "L1 ";
for (int k=0; k<vec.size(); ++k)
std::cout << vec.get_value(k) << " ";
std::cout << std::endl;
std::cout << "L2 ";
L2Vector vec2{0.25, 0.5, 1.0};
for (int k=0; k<vec2.size(); ++k)
std::cout << vec2.get_value(k) << " ";
std::cout << std::endl;
return 0;
}
This code is unnecessarily slow for large vectors because it calls get_normalization_constant() repeatedly, even though it doesn't change after construction (assuming modifiers like push_back have appropriately been disabled).
If I was only considering one form of normalization, I would simply use a double value to cache this result on construction:
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) {
normalization_constant = get_normalization_constant();
}
double get_value(int i) const {
return (*this)[i] / normalization_constant;
}
virtual double get_normalization_constant() const = 0;
double normalization_constant;
};
However, this understandably doesn't compile because the NormalizedVector constructor tries to call a pure virtual function (the derived virtual table is not available during base initialization).
Option 1:
Derived classes must manually call the normalization_constant = get_normalization_constant(); function in their constructors.
Option 2:
Objects define a virtual function for initializing the constant:
init_normalization_constant() {
normalization_constant = get_normalization_constant();
}
Objects are then constructed by a factory:
struct NormalizedVector : public std::vector<double> {
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) {
// init_normalization_constant();
}
double get_value(int i) const {
return (*this)[i] / normalization_constant;
}
virtual double get_normalization_constant() const = 0;
virtual void init_normalization_constant() {
normalization_constant = get_normalization_constant();
}
double normalization_constant;
};
// ...
// same code for derived types here
// ...
template <typename TYPE>
struct Factory {
template <typename ...ARGTYPES>
static TYPE construct_and_init(ARGTYPES...args) {
TYPE result(args...);
result.init_normalization_constant();
return result;
}
};
int main() {
L1Vector vec = Factory<L1Vector>::construct_and_init<std::initializer_list<double> >({0.25, 0.5, 1.0});
std::cout << "L1 ";
for (int k=0; k<vec.size(); ++k)
std::cout << vec.get_value(k) << " ";
std::cout << std::endl;
return 0;
}
Option 3:
Use an actual cache: get_normalization_constant is defined as a new type, CacheFunctor; the first time CacheFunctor is called, it saves the return value.
In Python, this works as originally coded, because the virtual table is always present, even in __init__ of a base class. In C++ this is much trickier.
I'd really appreciate the help; this comes up a lot for me. I feel like I'm getting the hang of good object oriented design in C++, but not always when it comes to making very efficient code (especially in the case of this sort of simple caching).
I suggest the non-virtual interface pattern. This pattern excels when you want a method to provide both common and unique functionality. (In this case, caching in common, computation in uniqueness.)
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
// UNTESTED
struct NormalizedVector : public std::vector<double> {
...
double normalization_constant;
bool cached;
virtual double do_get_normalization_constant() = 0;
double get_normalization_constant() {
if(!cached) {
cached = true;
normalization_constant = do_get_normalization_constant();
}
return normalization_constant;
};
P.s. You really ought not publicly derive from std::vector.
P.P.s. Invalidating the cache is as simple as setting cached to false.
Complete Solution
#include <vector>
#include <iostream>
#include <iterator>
#include <cmath>
#include <algorithm>
struct NormalizedVector : private std::vector<double> {
private:
typedef std::vector<double> Base;
protected:
using Base::operator[];
using Base::begin;
using Base::end;
public:
using Base::size;
NormalizedVector(std::initializer_list<double> init_list):
std::vector<double>(init_list) { }
double get_value(int i) const {
return (*this)[i] / get_normalization_constant();
}
virtual double do_get_normalization_constant() const = 0;
mutable bool normalization_constant_valid;
mutable double normalization_constant;
double get_normalization_constant() const {
if(!normalization_constant_valid) {
normalization_constant = do_get_normalization_constant();
normalization_constant_valid = true;
}
return normalization_constant;
}
void push_back(const double& value) {
normalization_constant_valid = false;
Base::push_back(value);
}
virtual ~NormalizedVector() {}
};
struct L1Vector : public NormalizedVector {
L1Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { get_normalization_constant(); }
double do_get_normalization_constant() const {
return std::accumulate(begin(), end(), 0.0);
}
};
struct L2Vector : public NormalizedVector {
L2Vector(std::initializer_list<double> init_list):
NormalizedVector(init_list) { get_normalization_constant(); }
double do_get_normalization_constant() const {
return std::sqrt(
std::accumulate(begin(), end(), 0.0,
[](double a, double b) { return a + b * b; } ) );
}
};
std::ostream&
operator<<(std::ostream& os, NormalizedVector& vec) {
for (int k=0; k<vec.size(); ++k)
os << vec.get_value(k) << " ";
return os;
}
int main() {
L1Vector vec{0.25, 0.5, 1.0};
std::cout << "L1 " << vec << "\n";
vec.push_back(2.0);
std::cout << "L1 " << vec << "\n";
L2Vector vec2{0.25, 0.5, 1.0};
std::cout << "L2 " << vec2 << "\n";
vec2.push_back(2.0);
std::cout << "L2 " << vec2 << "\n";
return 0;
}
A quick and dirty solution is to use static member variable.
double get_normalization_constant() const {
static double tot = 0.0;
if( tot == 0.0 )
for (int k=0; k<size(); ++k)
tot += (*this)[k];
return tot;
}
In this case, it will only be computed once.. and each time it will return the latest value.
NOTE:
This double tot, will be shared will all objects of same type. Don't use it if you will create many object of the type L1Vector