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
Related
might be a stupid question and if it is, let me know, I will delete it as soon as possible. The thing is I have to make a deep copy in class "Kambarys" (ignore mixed languages, I know I shouldn't do that). Program terminates after trying to call function second time. Probably the problem is my syntax in constructor copy, but I can't find the correct one anywhere. One of the requirements is to create langas, durys and kambarys in dynamic memory using "new" and delete windows vector and door in Kambarys destructor. Appreciate the help!
Requirements:
In the main method, use the new operator to create room k1, add windows and doors to it. Write a constructor Room (const Room & k) that would create a correct copy. In the method main, write another room k2. Calculate the length of the baseboards / wall area.
Perform the following steps: k2 = * k1; delete k1;
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
class Langas{
private:
float height;
float widht;
static int countL;
public:
Langas(float h, float w){
this->height=h;
this->widht=w;
countL++;
}
~Langas(){
--countL;
}
float getHeight(){
return height;
}
float getWidht(){
return widht;
}
static int getWindowCount(){
return countL;
}
};
class Durys{
private:
float heightD;
float widhtD;
static int countD;
public:
Durys(float hD, float wD){
this->heightD=hD;
this->widhtD=wD;
countD++;
}
~Durys(){
--countD;
}
float getHeightD(){
return heightD;
}
float getWidhtD(){
return widhtD;
}
static int getDoorCount(){
return countD;
}
};
class Kambarys{
private:
float heightK;
float widhtK;
float lenghtK;
public:
vector<Langas*> windows;
Durys* door;
Kambarys(float hK, float wK, float lK){
this->heightK=hK;
this->widhtK=wK;
this->lenghtK=lK;
}
Kambarys(const Kambarys &k){
this->door=k.door;
this->windows=k.windows;
heightK=k.heightK;
widhtK=k.widhtK;
lenghtK=k.lenghtK;
}
~Kambarys(){
door=NULL;
for(int i=0; i<windows.size(); i++){
delete windows[i];
}
windows.clear();
delete door;
}
float getHeightK(){
return heightK;
}
float getWidhtK(){
return widhtK;
}
float getLenghtK(){
return lenghtK;
}
void addWindow(Langas* w){
windows.push_back(w);
}
void addDoor(Durys *d){
door=d;
}
};
float countWallPlot(Kambarys* k){
float cWPlot=(2*k->getLenghtK()*k->getHeightK())+(2*k->getWidhtK()*k->getHeightK());
for(int i=0; i<k->windows.size(); i++){
cWPlot-=((k->windows[i]->getHeight()))*(k->windows[i]->getWidht());
}
cWPlot-=((k->door->getHeightD()))*(k->door->getWidhtD());
return cWPlot;
}
float countLenght(Kambarys* k){
float floorL=(k->getLenghtK()*k->getWidhtK()*2);
floorL-=(k->door->getWidhtD());
return floorL;
}
int Langas::countL=0;
int Durys::countD=0;
int main(){
Langas *langas1=new Langas(3.4, 1.2);
Durys *durys=new Durys(3.1, 1.5);
Langas *langas2=new Langas(6.4, 1.5);
Kambarys *k=new Kambarys(30.4, 40.1, 50.1);
Kambarys *k2=k;
k->addWindow(langas1);
k->addWindow(langas2);
k->addDoor(durys);
cout<<countWallPlot(k)<<" "<<countLenght(k)<<endl;
cout<<"Window count "<<Langas::getWindowCount()<<", door count "<<Durys::getDoorCount()<<endl;
k2=k;
delete k;
cout<<countWallPlot(k2)<<" "<<countLenght(k2)<<endl;
cout<<"Window count "<<Langas::getWindowCount()<<", door count "<<Durys::getDoorCount()<<endl;
}
You have to allocate memory for k2 and copy the object, not the pointer.
You have to allocate memory in the copy constructor and copy assignment operator.
door=NULL; before delete door; would skip the delete and cause a memory leak.
windows.clear(); is not necessary in the destructor. Keep your code simple.
EDIT: After you added "Perform the following steps: k2 = * k1; delete k1;" I made k2 an object, not a pointer.
#include <iostream>
#include <vector>
class Langas {
private:
float height;
float width;
static int count;
public:
Langas(float h, float w): height(h), width(w) {
++count;
}
~Langas() { --count; }
float getHeight() const { return height; }
float getWidht() const { return width; }
static int getWindowCount() { return count; }
};
class Durys {
private:
float height;
float width;
static int count;
public:
Durys(float h, float w): height(h), width(w) {
++count;
}
~Durys() { --count; }
float getHeight() const { return height; }
float getWidth() const { return width; }
static int getDoorCount() { return count; }
};
class Kambarys {
private:
float height;
float width;
float length;
public:
std::vector<Langas *> windows;
Durys *door = nullptr;
Kambarys(float hK, float wK, float lK): height(hK), width(wK), length(lK) {}
Kambarys(const Kambarys &k): height(k.height), width(k.width), length(k.length), windows(), door(k.door ? new Durys(k.door->getHeight(), k.door->getWidth()) : nullptr) {
for (const auto window : k.windows) {
windows.emplace_back(new Langas(window->getHeight(), window->getWidht()));
}
}
Kambarys &operator=(const Kambarys &k) {
door = k.door ? new Durys(k.door->getHeight(), k.door->getWidth()) : nullptr;
for (const auto window : k.windows) {
windows.emplace_back(new Langas(window->getHeight(), window->getWidht()));
}
height = k.height;
width = k.width;
length = k.length;
return *this;
}
~Kambarys() {
for (auto window : windows) {
delete window;
}
delete door;
}
float getHeight() const { return height; }
float getWidth() const { return width; }
float getLength() const { return length; }
void addWindow(Langas *w) { windows.emplace_back(w); }
void addDoor(Durys *d) { door = d; }
};
float countWallPlot(const Kambarys &k) {
float cWPlot = 2 * k.getLength() * k.getHeight() + 2 * k.getWidth() * k.getHeight();
for (const auto window : k.windows) {
cWPlot -= window->getHeight() * window->getWidht();
}
cWPlot -= k.door->getHeight() * k.door->getWidth();
return cWPlot;
}
float countLength(const Kambarys &k) {
float floor = k.getLength() * k.getWidth() * 2;
floor -= k.door->getWidth();
return floor;
}
int Langas::count = 0;
int Durys::count = 0;
int main() {
Langas *langas1 = new Langas(3.4, 1.2);
Durys *durys = new Durys(3.1, 1.5);
Langas *langas2 = new Langas(6.4, 1.5);
Kambarys *k = new Kambarys(30.4, 40.1, 50.1);
Kambarys k2(*k);
k->addWindow(langas1);
k->addWindow(langas2);
k->addDoor(durys);
std::cout << countWallPlot(*k) << " " << countLength(*k) << std::endl;
k2 = *k;
std::cout << "Window count " << Langas::getWindowCount() << ", door count " << Durys::getDoorCount() << std::endl;
delete k;
std::cout << countWallPlot(k2) << " " << countLength(k2) << std::endl;
std::cout << "Window count " << Langas::getWindowCount() << ", door count " << Durys::getDoorCount() << std::endl;
}
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 would like to return an array to a pointer, in a virtual function that is a member of a derived class of a template class. In details, my classes definition is:
Sampler.h
#ifndef SAMPLER_H
#define SAMPLER_H
template <class T>
class Sampler
{
public:
virtual T getnumber()=0;
virtual T* simulation(int n)=0;
};
class UniformSampler:public Sampler<double>
{
public:
virtual double getnumber();
virtual double* simulation(int n);
UniformSampler(double a=0.0, double b=1.0);
private:
double low_bound;
double up_bound;
};
#endif
The class Sampler is a template class in order to be able to derive an other sampler with vectors later. The implementation is:
Sampler.cpp
#include "Sampler.h"
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
//Uniform
UniformSampler::UniformSampler(double a, double b)
{
low_bound=a;
up_bound=b;
}
double UniformSampler::getnumber()
{
int myrand=rand();
while((myrand==0)||(myrand==RAND_MAX)){myrand = rand(); } //We want a number in (0, RAND_MAX).
double myuni = myrand/static_cast<double>(RAND_MAX); //Create a number in (0,1).
return low_bound + myuni*(up_bound-low_bound);
}
double* UniformSampler::simulation(int n){
double simulations[n];
for(int i=0; i<n; i++){
simulations[i] = this->getnumber();
}
return simulations;
}
My problem is that, when I try to call this program in the main(), it looks like the assignment of the pointer doesn't work. Here is my main.cpp:
#include <iostream>
#include <math.h>
#include <cstdlib>
#include <time.h>
using namespace std;
#include "Sampler.h"
int main(){
srand(time(0));
int n=10;
double *unif = new double[n];
UniformSampler uni;
unif = uni.simulation(n);
for ( int i = 0; i < n; i++ ) {
cout << "*(p + " << i << ") : ";
cout << *(unif + i) << endl;
}
delete[] unif;
return 0;
}
When I run it, it doesn't print any of the elements that unif points to. I don't understand what is wrong there.
UniformSampler::simulation is twice wrong:
double simulations[n]; uses VLA extension, so not C++ standard compliant.
you return pointer on local variable, so dangling pointer.
Solution: use std::vector instead.
#include <vector>
template <class T>
class Sampler
{
public:
virtual ~Sampler() = default;
virtual T getnumber() = 0;
virtual std::vector<T> simulation(int n) = 0;
};
class UniformSampler:public Sampler<double>
{
public:
explicit UniformSampler(double a=0.0, double b=1.0);
double getnumber() overrid;
std::vector<double> simulation(int n) override
{
std::vector<double> res(n);
for (auto& val : res){
res = getnumber();
}
return res;
}
private:
double low_bound;
double up_bound;
};
int main(){
srand(time(0));
constexpr int n = 10;
UniformSampler uni;
auto unif = uni.simulation(n);
for (int i = 0; i < n; i++ ) {
std::cout << "p[" << i << "]: " << unif[i] << endl;
}
}
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 want to be able to create not only a Chart, but a BarChart, and to pass in a vector of doubles and have that data put into the private member data. How would I do this in the BarChart (child) class of Chart? Also I am still confused as to pass by pointers, reference, or value, so I'm not sure if I am passing it correctly here. Please let me know how to fix this mess. Thank you for your help!
#include <vector>
using namespace std;
class Chart
{
public:
Chart(vector<double> &d) : data(d) {}
virtual void draw() const;
protected:
double value_at(int index) const; // ... only allows access, not modification
int get_size() const
{
return data.size();
}
private:
vector<double> &data; // Now data is safely private
};
class BarChart : public Chart
{
public:
virtual void draw() const
{
for (int x = 0; x < get_size() - 1; x++)
{
cout << value_at(x) << " ";
for (int y = 0; y < value_at(x); y++)
{
cout << "*";
}
cout << endl;
}
}
};
#include <iostream>
#include "chart.h"
#include <vector>
int main(int argc, char** argv)
{
vector<double> doubles;
doubles.resize(4);
for (int x = 0; x < 4; x++)
{
doubles[x] = x + 1.7;
}
BarChart c(doubles);
return 0;
}
I think this is what you want now. By the way you have to read these things for your future :)
How access modifiers works in inheritance
How constructors initialize in inheritance
What is the difference between pass by reference and pass by value.
These all you can read in the internet. Only thing is need to spend some time for find and read.
#include <vector>
#include <iostream>
class Chart
{
public:
Chart(std::vector<double> &d) : data(d) {}
virtual void draw(){}
double value_at(int index) const{ return data[index];}
int get_size() const{return data.size();}
private:
std::vector<double> &data;
};
class BarChart : public Chart
{
public:
BarChart(std::vector<double> &d):Chart(d)
{
}
virtual void draw()
{
for (int x = 0; x < get_size() - 1; x++)
{
std::cout << value_at(x) << " ";
for (int y = 0; y < value_at(x); y++)
{
std::cout << "*";
}
std::cout << std::endl;
}
}
};
int main()
{
std::vector<double> barchartData;
barchartData.push_back(10);
barchartData.push_back(20);
BarChart barchart(barchartData);
std::cout << "Barchart size :" << barchart.get_size() << std::endl;
std::vector<double> chartData;
chartData.push_back(500);
chartData.push_back(600);
Chart chart(chartData);
std::cout << "Chart size :" << chart.get_size() << std::endl;
return 0;
}