I came across this strange code snippet which compiles fine:
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
return 0;
}
Why does C++ have this pointer to a non-static data member of a class? What is the use of this strange pointer in real code?
It's a "pointer to member" - the following code illustrates its use:
#include <iostream>
using namespace std;
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
Car c1;
c1.speed = 1; // direct access
cout << "speed is " << c1.speed << endl;
c1.*pSpeed = 2; // access via pointer to member
cout << "speed is " << c1.speed << endl;
return 0;
}
As to why you would want to do that, well it gives you another level of indirection that can solve some tricky problems. But to be honest, I've never had to use them in my own code.
Edit: I can't think off-hand of a convincing use for pointers to member data. Pointer to member functions can be used in pluggable architectures, but once again producing an example in a small space defeats me. The following is my best (untested) try - an Apply function that would do some pre &post processing before applying a user-selected member function to an object:
void Apply( SomeClass * c, void (SomeClass::*func)() ) {
// do hefty pre-call processing
(c->*func)(); // call user specified function
// do hefty post-call processing
}
The parentheses around c->*func are necessary because the ->* operator has lower precedence than the function call operator.
This is the simplest example I can think of that conveys the rare cases where this feature is pertinent:
#include <iostream>
class bowl {
public:
int apples;
int oranges;
};
int count_fruit(bowl * begin, bowl * end, int bowl::*fruit)
{
int count = 0;
for (bowl * iterator = begin; iterator != end; ++ iterator)
count += iterator->*fruit;
return count;
}
int main()
{
bowl bowls[2] = {
{ 1, 2 },
{ 3, 5 }
};
std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::apples) << " apples\n";
std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::oranges) << " oranges\n";
return 0;
}
The thing to note here is the pointer passed in to count_fruit. This saves you having to write separate count_apples and count_oranges functions.
Another application are intrusive lists. The element type can tell the list what its next/prev pointers are. So the list does not use hard-coded names but can still use existing pointers:
// say this is some existing structure. And we want to use
// a list. We can tell it that the next pointer
// is apple::next.
struct apple {
int data;
apple * next;
};
// simple example of a minimal intrusive list. Could specify the
// member pointer as template argument too, if we wanted:
// template<typename E, E *E::*next_ptr>
template<typename E>
struct List {
List(E *E::*next_ptr):head(0), next_ptr(next_ptr) { }
void add(E &e) {
// access its next pointer by the member pointer
e.*next_ptr = head;
head = &e;
}
E * head;
E *E::*next_ptr;
};
int main() {
List<apple> lst(&apple::next);
apple a;
lst.add(a);
}
Here's a real-world example I am working on right now, from signal processing / control systems:
Suppose you have some structure that represents the data you are collecting:
struct Sample {
time_t time;
double value1;
double value2;
double value3;
};
Now suppose that you stuff them into a vector:
std::vector<Sample> samples;
... fill the vector ...
Now suppose that you want to calculate some function (say the mean) of one of the variables over a range of samples, and you want to factor this mean calculation into a function. The pointer-to-member makes it easy:
double Mean(std::vector<Sample>::const_iterator begin,
std::vector<Sample>::const_iterator end,
double Sample::* var)
{
float mean = 0;
int samples = 0;
for(; begin != end; begin++) {
const Sample& s = *begin;
mean += s.*var;
samples++;
}
mean /= samples;
return mean;
}
...
double mean = Mean(samples.begin(), samples.end(), &Sample::value2);
Note Edited 2016/08/05 for a more concise template-function approach
And, of course, you can template it to compute a mean for any forward-iterator and any value type that supports addition with itself and division by size_t:
template<typename Titer, typename S>
S mean(Titer begin, const Titer& end, S std::iterator_traits<Titer>::value_type::* var) {
using T = typename std::iterator_traits<Titer>::value_type;
S sum = 0;
size_t samples = 0;
for( ; begin != end ; ++begin ) {
const T& s = *begin;
sum += s.*var;
samples++;
}
return sum / samples;
}
struct Sample {
double x;
}
std::vector<Sample> samples { {1.0}, {2.0}, {3.0} };
double m = mean(samples.begin(), samples.end(), &Sample::x);
EDIT - The above code has performance implications
You should note, as I soon discovered, that the code above has some serious performance implications. The summary is that if you're calculating a summary statistic on a time series, or calculating an FFT etc, then you should store the values for each variable contiguously in memory. Otherwise, iterating over the series will cause a cache miss for every value retrieved.
Consider the performance of this code:
struct Sample {
float w, x, y, z;
};
std::vector<Sample> series = ...;
float sum = 0;
int samples = 0;
for(auto it = series.begin(); it != series.end(); it++) {
sum += *it.x;
samples++;
}
float mean = sum / samples;
On many architectures, one instance of Sample will fill a cache line. So on each iteration of the loop, one sample will be pulled from memory into the cache. 4 bytes from the cache line will be used and the rest thrown away, and the next iteration will result in another cache miss, memory access and so on.
Much better to do this:
struct Samples {
std::vector<float> w, x, y, z;
};
Samples series = ...;
float sum = 0;
float samples = 0;
for(auto it = series.x.begin(); it != series.x.end(); it++) {
sum += *it;
samples++;
}
float mean = sum / samples;
Now when the first x value is loaded from memory, the next three will also be loaded into the cache (supposing suitable alignment), meaning you don't need any values loaded for the next three iterations.
The above algorithm can be improved somewhat further through the use of SIMD instructions on eg SSE2 architectures. However, these work much better if the values are all contiguous in memory and you can use a single instruction to load four samples together (more in later SSE versions).
YMMV - design your data structures to suit your algorithm.
You can later access this member, on any instance:
int main()
{
int Car::*pSpeed = &Car::speed;
Car myCar;
Car yourCar;
int mySpeed = myCar.*pSpeed;
int yourSpeed = yourCar.*pSpeed;
assert(mySpeed > yourSpeed); // ;-)
return 0;
}
Note that you do need an instance to call it on, so it does not work like a delegate.
It is used rarely, I've needed it maybe once or twice in all my years.
Normally using an interface (i.e. a pure base class in C++) is the better design choice.
IBM has some more documentation on how to use this. Briefly, you're using the pointer as an offset into the class. You can't use these pointers apart from the class they refer to, so:
int Car::*pSpeed = &Car::speed;
Car mycar;
mycar.*pSpeed = 65;
It seems a little obscure, but one possible application is if you're trying to write code for deserializing generic data into many different object types, and your code needs to handle object types that it knows absolutely nothing about (for example, your code is in a library, and the objects into which you deserialize were created by a user of your library). The member pointers give you a generic, semi-legible way of referring to the individual data member offsets, without having to resort to typeless void * tricks the way you might for C structs.
It makes it possible to bind member variables and functions in the uniform manner. The following is example with your Car class. More common usage would be binding std::pair::first and ::second when using in STL algorithms and Boost on a map.
#include <list>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
class Car {
public:
Car(int s): speed(s) {}
void drive() {
std::cout << "Driving at " << speed << " km/h" << std::endl;
}
int speed;
};
int main() {
using namespace std;
using namespace boost::lambda;
list<Car> l;
l.push_back(Car(10));
l.push_back(Car(140));
l.push_back(Car(130));
l.push_back(Car(60));
// Speeding cars
list<Car> s;
// Binding a value to a member variable.
// Find all cars with speed over 60 km/h.
remove_copy_if(l.begin(), l.end(),
back_inserter(s),
bind(&Car::speed, _1) <= 60);
// Binding a value to a member function.
// Call a function on each car.
for_each(s.begin(), s.end(), bind(&Car::drive, _1));
return 0;
}
You can use an array of pointer to (homogeneous) member data to enable a dual, named-member (i.e. x.data) and array-subscript (i.e. x[idx]) interface.
#include <cassert>
#include <cstddef>
struct vector3 {
float x;
float y;
float z;
float& operator[](std::size_t idx) {
static float vector3::*component[3] = {
&vector3::x, &vector3::y, &vector3::z
};
return this->*component[idx];
}
};
int main()
{
vector3 v = { 0.0f, 1.0f, 2.0f };
assert(&v[0] == &v.x);
assert(&v[1] == &v.y);
assert(&v[2] == &v.z);
for (std::size_t i = 0; i < 3; ++i) {
v[i] += 1.0f;
}
assert(v.x == 1.0f);
assert(v.y == 2.0f);
assert(v.z == 3.0f);
return 0;
}
One way I've used it is if I have two implementations of how to do something in a class and I want to choose one at run-time without having to continually go through an if statement i.e.
class Algorithm
{
public:
Algorithm() : m_impFn( &Algorithm::implementationA ) {}
void frequentlyCalled()
{
// Avoid if ( using A ) else if ( using B ) type of thing
(this->*m_impFn)();
}
private:
void implementationA() { /*...*/ }
void implementationB() { /*...*/ }
typedef void ( Algorithm::*IMP_FN ) ();
IMP_FN m_impFn;
};
Obviously this is only practically useful if you feel the code is being hammered enough that the if statement is slowing things done eg. deep in the guts of some intensive algorithm somewhere. I still think it's more elegant than the if statement even in situations where it has no practical use but that's just my opnion.
Pointers to classes are not real pointers; a class is a logical construct and has no physical existence in memory, however, when you construct a pointer to a member of a class it gives an offset into an object of the member's class where the member can be found; This gives an important conclusion: Since static members are not associated with any object so a pointer to a member CANNOT point to a static member(data or functions) whatsoever
Consider the following:
class x {
public:
int val;
x(int i) { val = i;}
int get_val() { return val; }
int d_val(int i) {return i+i; }
};
int main() {
int (x::* data) = &x::val; //pointer to data member
int (x::* func)(int) = &x::d_val; //pointer to function member
x ob1(1), ob2(2);
cout <<ob1.*data;
cout <<ob2.*data;
cout <<(ob1.*func)(ob1.*data);
cout <<(ob2.*func)(ob2.*data);
return 0;
}
Source: The Complete Reference C++ - Herbert Schildt 4th Edition
Here is an example where pointer to data members could be useful:
#include <iostream>
#include <list>
#include <string>
template <typename Container, typename T, typename DataPtr>
typename Container::value_type searchByDataMember (const Container& container, const T& t, DataPtr ptr) {
for (const typename Container::value_type& x : container) {
if (x->*ptr == t)
return x;
}
return typename Container::value_type{};
}
struct Object {
int ID, value;
std::string name;
Object (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};
std::list<Object*> objects { new Object(5,6,"Sam"), new Object(11,7,"Mark"), new Object(9,12,"Rob"),
new Object(2,11,"Tom"), new Object(15,16,"John") };
int main() {
const Object* object = searchByDataMember (objects, 11, &Object::value);
std::cout << object->name << '\n'; // Tom
}
Suppose you have a structure. Inside of that structure are
* some sort of name
* two variables of the same type but with different meaning
struct foo {
std::string a;
std::string b;
};
Okay, now let's say you have a bunch of foos in a container:
// key: some sort of name, value: a foo instance
std::map<std::string, foo> container;
Okay, now suppose you load the data from separate sources, but the data is presented in the same fashion (eg, you need the same parsing method).
You could do something like this:
void readDataFromText(std::istream & input, std::map<std::string, foo> & container, std::string foo::*storage) {
std::string line, name, value;
// while lines are successfully retrieved
while (std::getline(input, line)) {
std::stringstream linestr(line);
if ( line.empty() ) {
continue;
}
// retrieve name and value
linestr >> name >> value;
// store value into correct storage, whichever one is correct
container[name].*storage = value;
}
}
std::map<std::string, foo> readValues() {
std::map<std::string, foo> foos;
std::ifstream a("input-a");
readDataFromText(a, foos, &foo::a);
std::ifstream b("input-b");
readDataFromText(b, foos, &foo::b);
return foos;
}
At this point, calling readValues() will return a container with a unison of "input-a" and "input-b"; all keys will be present, and foos with have either a or b or both.
Just to add some use cases for #anon's & #Oktalist's answer, here's a great reading material about pointer-to-member-function and pointer-to-member-data.
https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-ptmf4.pdf
with pointer to member, we can write generic code like this
template<typename T, typename U>
struct alpha{
T U::*p_some_member;
};
struct beta{
int foo;
};
int main()
{
beta b{};
alpha<int, beta> a{&beta::foo};
b.*(a.p_some_member) = 4;
return 0;
}
I love the * and & operators:
struct X
{
int a {0};
int *ptr {NULL};
int &fa() { return a; }
int *&fptr() { return ptr; }
};
int main(void)
{
X x;
int X::*p1 = &X::a; // pointer-to-member 'int X::a'. Type of p1 = 'int X::*'
x.*p1 = 10;
int *X::*p2 = &X::ptr; // pointer-to-member-pointer 'int *X::ptr'. Type of p2 = 'int *X::*'
x.*p2 = nullptr;
X *xx;
xx->*p2 = nullptr;
int& (X::*p3)() = X::fa; // pointer-to-member-function 'X::fa'. Type of p3 = 'int &(X::*)()'
(x.*p3)() = 20;
(xx->*p3)() = 30;
int *&(X::*p4)() = X::fptr; // pointer-to-member-function 'X::fptr'. Type of p4 = 'int *&(X::*)()'
(x.*p4)() = nullptr;
(xx->*p4)() = nullptr;
}
Indeed all is true as long as the members are public, or static
I think you'd only want to do this if the member data was pretty large (e.g., an object of another pretty hefty class), and you have some external routine which only works on references to objects of that class. You don't want to copy the member object, so this lets you pass it around.
A realworld example of a pointer-to-member could be a more narrow aliasing constructor for std::shared_ptr:
template <typename T>
template <typename U>
shared_ptr<T>::shared_ptr(const shared_ptr<U>, T U::*member);
What that constructor would be good for
assume you have a struct foo:
struct foo {
int ival;
float fval;
};
If you have given a shared_ptr to a foo, you could then retrieve shared_ptr's to its members ival or fval using that constructor:
auto foo_shared = std::make_shared<foo>();
auto ival_shared = std::shared_ptr<int>(foo_shared, &foo::ival);
This would be useful if want to pass the pointer foo_shared->ival to some function which expects a shared_ptr
https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
Pointer to members are C++'s type safe equivalent for C's offsetof(), which is defined in stddef.h: Both return the information, where a certain field is located within a class or struct. While offsetof() may be used with certain simple enough classes also in C++, it fails miserably for the general case, especially with virtual base classes. So pointer to members were added to the standard. They also provide easier syntax to reference an actual field:
struct C { int a; int b; } c;
int C::* intptr = &C::a; // or &C::b, depending on the field wanted
c.*intptr += 1;
is much easier than:
struct C { int a; int b; } c;
int intoffset = offsetof(struct C, a);
* (int *) (((char *) (void *) &c) + intoffset) += 1;
As to why one wants to use offsetof() (or pointer to members), there are good answers elsewhere on stackoverflow. One example is here: How does the C offsetof macro work?
For example, I have this code.
#include <iostream>
using namespace std;
int main()
{
int x = 5; //Original variable
int &y = x; //Reference variable to x.
y = 10; //Modifying reference variable.
cout<<x<<" "<<y<<endl;
x = 5; //Modifying original variable.
cout<<x<<" "<<y<<endl;
}
It gives the expected output.
10 10
5 5
Shows that modifying either the original variable or the reference variable changes them both - Pretty obvious.
My question is that:
Can a reference variable be defined in such a way that modifying it DOES NOT modify the original variable?
I know then it wouldn't be called a reference variable.
To make things more clear,
Modifying x should modify y, but modifying y should not modify x. That is, y should be an independent copy of x, but should change as and when x changes.
Can this be possible?
Yes, I can create my own logic to emulate this, but I was wondering if C++ catered to this by default.
There is no language construct that can immediately give you what you seek but you can implement it fairly straightforward by encapsulating x and y.
struct XChangesY{
set_x(int x_and_y){ y = x = x_and_y; }
set_y(int y_){ y = y_; }
int get_x(){ return x; }
int get_y(){ return y; }
private:
int x;
int y;
}
No, what you want to do isn't possible. Consider what happens if you modify both y and x. Where does y take its value then? From the updated value of x which should modify both x and y, or from the updated value of y which should update y only and not x?
The only way forward is to implement your own logic. In any case, you need to have two int variables.
Sure, but it's not elegant--
template<typename T>
class C
{
public:
C(T t) : m_t(new T(t)), t_local(t), is_copy(false) {}
C(const C& c) : m_t(c.m_t), t_local(t), is_copy(true) {}
T Get() { return *m_t; }
T GetLocal() { return t_local; }
void Set(T t)
{
t_local = t;
if (!is_copy) *m_t = t;
}
private:
T* m_t;
T t_local;
bool is_copy;
};
And your setup creates an ambiguity when it comes to evaluating y, after both it has been changed--do you want the value of x, or the new, different value of y? I don't see any way to avoid creating separate methods for each case.
C++ does not provide a mechanism for doing this automatically, but you can make a class that supports the behavior that you are trying to make.
Here is a grossly oversimplified version of what you can do:
class IntRef {
int *ptr;
int copy;
public:
IntRef(int& d) : ptr(&d) {}
IntRef& operator=(const int& rhs) {
// Detach from the original on assignment
copy = rhs;
ptr = ©
}
operator int() const {
return *ptr;
}
};
int main() {
int x = 5; //Original variable
IntRef y(x); //Reference variable to x.
x = 5; //Modifying original variable.
cout<<x<<" "<<y<<endl;
y = 10; //Modifying reference variable.
cout<<x<<" "<<y<<endl;
return 0;
}
Demo.
This prints
5 5
5 10
The idea of the implementation above is to keep a pointer pointing to the original value for as long as y is not assigned. After the assignment the pointer is switched to a copy that is kept internally.
What you're looking for isn't inherently built-in the language - having two variables sharing the same value, changing one changes both but changing the other one only changes one.
That question though is similar to shared pointers and reference counters. For example, when you make a copy of a std::string, the content of the string isn't copied. A new string object is created with a pointer to the same data as the first string, and a reference counter.
So both strings share the same data. But when you change one - either one - and the reference counter is more than one, then that string dissociates itself and copies the data, and both strings are no longer linked. This is in order to avoid duplicated long strings of data when there's no need.
The same thing happens with Qt containers (QByteArray, QMap, QList, ...).
Another way to look at your problem is a logic of watcher - data received from outside updates the internal value, but the internal value can be changed by other means. Qt's signals/slot feature can be used to do that naturally, or you can easily implement your own logic to do that yourself.
Seems like what you want is copy-on-write semantics. Something like this might work for you, but is easily abused:
template <class T>
class cow_ptr
{
public:
using ref_ptr = std::shared_ptr<T>;
private:
ref_ptr m_sp;
bool m_original; //don't detach the original
void detach()
{
T* tmp = m_sp.get();
if( !( tmp == 0 || m_sp.unique() || m_original ) ) {
m_sp = ref_ptr( new T {*tmp} );
}
}
public:
cow_ptr(T* t)
: m_sp{t}, m_original{true}
{}
cow_ptr(const ref_ptr& refptr)
: m_sp{refptr}, m_original{true}
{}
cow_ptr(const cow_ptr& cowptr)
: m_sp{cowptr.m_sp}, m_original{false}
{}
cow_ptr& operator=(const cow_ptr& rhs)
{
m_sp = rhs.m_sp;
return *this;
}
const T& operator*() const
{
return *m_sp;
}
T& operator*()
{
detach();
return *m_sp;
}
const T* operator->() const
{
return m_sp.operator->();
}
T* operator->()
{
detach();
return m_sp.operator->();
}
};
Then you can use it like this:
int main()
{
auto x = cow_ptr<int>{ new int{5} };
auto y = x;
const auto &yr = y; //so dereferencing doesn't detach
cout<<*x<<" "<<*yr<<endl; //5 5
*x = 10;
cout<<*x<<" "<<*yr<<endl; //10 10 (updating x updated y)
*y = 15;
cout<<*x<<" "<<*yr<<endl; //10 15 (updating y did not update x)
//from now on, changing x will not change y
}
Background: I'm stuck to arm-arago-linux-gnueabi-g++ (GCC) 4.3.3. Although answers that requires C++11 or later is also appreciated, please explicitly express any language requirement later than C++03.
The object's constructor fills values into tables to be used by the algorithm.
As those table does not change and are not supposed to be changed, I want the them to be const, how do I do that?
Difficulty #1, the values are computationally generated, and I don't want to hard code them in a source file.
Difficulty #2, the computing sometimes depends on inputs that are only available at runtime.
Difficulty #3, I don't know why but I don't want the array to be static, even though the values might be the same for all objects(cases where the values does not depend on runtime input).
Difficulty #4, it's an array, so initializer list in C++03 won't work.
Edit1:
A few weeks after this post, I found both std::array and std::vector are very good alternative to C-style array when std::array is not available.
You can encapsulate the tables in a private type, with a single const instance of that type in your object, then forward the relevant constructor parameters to the private object; this works because even a const object is non-const during its construction.
For example:
class MyClass {
const struct Tables {
double x[1000];
double y[200];
Tables(int i, double d) {
x[i] = d;
y[200 - i] = -d;
}
} tables;
public:
MyClass(int i, double d) : tables(i, d) {}
};
MyClass c(20, 5.5);
Another technique is to build the tables in an ephemeral mutable array whose lifetime is bounded by the lifetime of the constructor, then initialize the const array from those mutable arrays.
Using C++11 std::array (since array types can't be copy-initialized):
class MyClass {
static std::array<double, 1000> buildArray(...) {
std::array<double, 1000> array;
... // fill array
return array;
}
const std::array<double, 1000> mArray;
public:
MyClass(...) : mArray(buildArray(...)) {}
};
Note that std::array is easy to express in C++03; it doesn't depend on any C++11 language features.
If you're worried about the overhead of returning a large array, instrument it - even C++03 compilers are capable of optimising large array returns.
I think you could implement a class containing the actual non const array. That way you can easily compute the values in a constructor.
Then this class would only have to implement the operator[] to be usable as an array. Or it could also simply return a const reference to the array.
Implementation example :
#include <iostream>
using namespace std;
class const_array {
int *arr;
size_t size;
public:
const_array(size_t size, int typ): size(size) {
arr = new int[size];
size_t i;
int val = 0;
for (i=0; i<size; i++) {
val += typ;
arr[i] = val;
}
}
const_array(const const_array & src): size(src.size) {
arr = new int[size];
size_t i;
for (i=0; i<size; i++) {
arr[i] = src.arr[i];
}
}
~const_array() {
delete[] arr;
}
const int * const getArray() const {
return arr;
}
int getSize() const {
return size;
}
const int& operator[](int i) {
return arr[i];
}
};
int main() {
const_array a(16, 4);
// int *arr = a.getArray(); error
const int *arr = a.getArray();
int j = a[2];
int k = arr[2];
// int * pj = &(a[2]); error
const int * pj = &(a[2]);
const int * pk = &(arr[2]);
cout << "a[2]=" << j << " (" << pj << ") - a.getArray[2]="
<< j << " (" << pj << ")" << endl;
return 0;
}
I have a class with a multidimensional array:
it is possible to create a one, two, ..., n dimensional array with this class
if the array has n dimensions, i want to use n operator[] to get an object:
example:
A a({2,2,2,2}];
a[0][1][1][0] = 5;
but array is not a vector of pointer which lead to other vectors etc...
so i want the operator[] to return a class object until the last dimension, then return a integer
This is a strongly simplified code, but it shows my problem:
The error i receive: "[Error] cannot convert 'A::B' to 'int' in initialization"
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <iostream> // cin, cout...
class A {
private:
static int* a;
public:
static int dimensions;
A(int i=0) {
dimensions = i;
a = new int[5];
for(int j=0; j<5; j++) a[j]=j;
};
class B{
public:
B operator[](std::ptrdiff_t);
};
class C: public B{
public:
int& operator[](std::ptrdiff_t);
};
B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
B res;
if (dimensions <= 1){
res = C();
}
else{
res = B();
}
dimensions--;
return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
B res;
if (dimensions <=1){
res = B();
}
else{
res = C();
}
dimensions--;
return res;
}
int& A::C::operator[](std::ptrdiff_t i){
return *(a+i);
}
int main(){
A* obj = new A(5);
int res = obj[1][1][1][1][1];
std::cout<< res << std::endl;
}
The operator[] is evaluated from left to right in obj[1][1]...[1], so obj[1] returns a B object. Suppose now you just have int res = obj[1], then you'll assign to a B object (or C object in the case of multiple invocations of []) an int, but there is no conversion from B or C to int. You probably need to write a conversion operator, like
operator int()
{
// convert to int here
}
for A, B and C, as overloaded operators are not inherited.
I got rid of your compiling error just by writing such operators for A and B (of course I have linking errors since there are un-defined functions).
Also, note that if you want to write something like obj[1][1]...[1] = 10, you need to overload operator=, as again there is no implicit conversion from int to A or your proxy objects.
Hope this makes sense.
PS: see also #Oncaphillis' comment!
vsoftco is totally right, you need to implement an overload operator if you want to actually access your elements. This is necessary if you want it to be dynamic, which is how you describe it. I actually thought this was an interesting problem, so I implemented what you described as a template. I think it works, but a few things might be slightly off. Here's the code:
template<typename T>
class nDimArray {
using thisT = nDimArray<T>;
T m_value;
std::vector<thisT*> m_children;
public:
nDimArray(std::vector<T> sizes) {
assert(sizes.size() != 0);
int thisSize = sizes[sizes.size() - 1];
sizes.pop_back();
m_children.resize(thisSize);
if(sizes.size() == 0) {
//initialize elements
for(auto &c : m_children) {
c = new nDimArray(T(0));
}
} else {
//initialize children
for(auto &c : m_children) {
c = new nDimArray(sizes);
}
}
}
~nDimArray() {
for(auto &c : m_children) {
delete c;
}
}
nDimArray<T> &operator[](const unsigned int index) {
assert(!isElement());
assert(index < m_children.size());
return *m_children[index];
}
//icky dynamic cast operators
operator T() {
assert(isElement());
return m_value;
}
T &operator=(T value) {
assert(isElement());
m_value = value;
return m_value;
}
private:
nDimArray(T value) {
m_value = value;
}
bool isElement() const {
return m_children.size() == 0;
}
//no implementation yet
nDimArray(const nDimArray&);
nDimArray&operator=(const nDimArray&);
};
The basic idea is that this class can either act as an array of arrays, or an element. That means that in fact an array of arrays COULD be an array of elements! When you want to get a value, it tries to cast it to an element, and if that doesn't work, it just throws an assertion error.
Hopefully it makes sense, and of course if you have any questions ask away! In fact, I hope you do ask because the scope of the problem you describe is greater than you probably think it is.
It could be fun to use a Russian-doll style template class for this.
// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
foo<d-1, n> data[n];
public:
foo<d-1, n>& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
int data[n];
public:
int& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
int main(int argc, char** argv)
{
foo<3, 10> myFoo;
for(int i=0; i<10; ++i)
for(int j=0; j<10; ++j)
for(int k=0; k<10; ++k)
myFoo[i][j][k] = i*10000 + j*100 + k;
return myFoo[9][9][9]; // would be 090909 in this case
}
Each dimension keeps an array of previous-dimension elements. Dimension 1 uses the base specialization that tracks a 1D int array. Dimension 2 would then keep an array of one-dimentional arrays, D3 would have an array of two-dimensional arrays, etc. Then access looks the same as native multi-dimensional arrays. I'm using arrays inside the class in my example. This makes all the memory contiguous for the n-dimensional arrays, and doesn't require dynamic allocations inside the class. However, you could provide the same functionality with dynamic allocation as well.
I'm trying to create my own version of an array called a safearray, to test my knowledge of operator overloading and creating proper class's and such.
I'm encountering two errors.
SafeArray.h:11:15: error: ‘const int SafeArray::operator’ cannot be overloaded
SafeArray.h:10:10: error: with ‘int& SafeArray::operator’
My code is split between three files.
Main.cpp
#include <cstdlib>
#include <iostream>
#include "SafeArray.h"
using namespace std;
int main(int argc, char** argv) {
SafeArray a(10); // 10 integer elements
for (int i = 0; i < a.length(); i++) {
cout << i << " " << a[i] << "s" << endl; // values initialise to 0
}
cout << endl << a[1]; // Program exits here.
a[3] = 42;
cout << a[3];
a[10] = 10;
cout << a[10];
a[-1] = -1; // out-of-bounds is "safe"?
SafeArray b(20); // another array
b = a; // array assignment
for (int i = 0; i < b.length(); i++) {
cout << b[i] << endl; // values copied from a
}
return 0;
}
SafeArray.h
#ifndef SAFEARRAY_H
#define SAFEARRAY_H
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
// const SafeArray operator= (const SafeArray&);
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
SafeArray(SafeArray const &other);
~SafeArray();
private:
int length_;
int *array;
//int array[];
};
#endif /* SAFEARRAY_H */
SafeArray.cpp
#include "SafeArray.h"
#include <iostream>
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
int SafeArray::length() {
return this->length_;
}
int SafeArray::boundsCheck(int y) {
}
int& SafeArray::operator[] (int y) {
return array[y];
}
SafeArray::~SafeArray() {
delete [] array;
}
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Your class definition isn't valid. int array[] is an incomplete type, which must not appear as a (non-static) class member. Some compilers accept this as a synonym for int array[0], but zero-sized arrays are not valid in C++, either (only in C99).
In short, you cannot write your code the way you do. You need to learn about dynamic allocation and manage your own memory. Check out how std::vector is implemented.
In C++11, I might recommend a std::unique_ptr<int[]> array as a quick-fix approach, to be initialized as array(new int[x]).
Actually int array[] is valid, and may appear as a class member. The following compiles with strict C++11 conformance:
class foo
{
public:
foo() {}
int length;
int A[];
};
void ralph()
{
foo *bar = (foo *)new int[ 21 ];
bar->length = 20;
bar->A[0] = 1;
}
This is legal, and has its advantages (occasionally). Although it is not commonly used.
However, I suspect that the OP wanted something more along the lines of
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
int& operator[] (int y);
const int operator [] (const int y) // you need this one too.
private:
int length_;
int *array;
};
along with
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
As #Kerrek already pointed out, your class definition is clearly wrong (shouldn't compile).
To fix it, you want to change the definition to something like:
int *array;
Then in your default ctor you could use something like this:
SafeArray::SafeArray(unsigned size = 0)
: array(new int[size])
{
for (unsigned i=0; i<size; i++)
array[i] = 0;
}
Then, yes, you'll need to write an assignment operator. The usual way is called the copy and swap idiom. You create a copy, then swap the contents of the current one with those of the copy:
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
Along with that, you'll need a copy constructor that makes a copy of the data as well:
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Finally, you'll need a destructor to destroy an object and (particularly) delete the memory it holds:
SafeArray::~SafeArray() {
delete [] array;
}
Then realize that all of that is an ugly mess that will never really work well. In particular, the basic methodology is restricted to an array that's basically fixed in size. As long as you only store ints, it's fairly easy to overlook the problems, and make a dynamic array that (sort of) works. When/if you want to store some other type, however, you just about need to separate allocating memory from initializing objects in that memory, which means throwing away essentially all the code above, and replacing it with something that:
keeps track of the array size and allocation size separately
allocates memory with ::operator new, an Allocator object, or something else similar
uses placement new to initialize objects in the memory when needed.
uses explicit destructor calls to destroy the objects
uses ::operator delete to release memory
and so on. To summarize, std::vector is not a trivial piece of work.
The error message refers to these two lines:
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
Your error message says that (int y) and (const int y) are too similar to be two different overloads of the [] operator. You cannot overload on (int y) and (const int y) because the calls would all be ambiguous.
You probably meant to return a const int if your SafeArray is const, but return an int& if your SafeArray is not const. In that case, you declare the second function to apply to const SafeArray, by putting the word const after the parameter list. This is what you should write in SafeArray.h:
int& operator[] (int y);
const int operator [] (int y) const; // you need this one too.
You would then have to write both of these functions in SafeArray.cpp:
int& SafeArray::operator[] (int y) {
return array[y];
}
const int SafeArray::operator[] (int y) const { // you need this one too.
return array[y];
}