Initialize a static member of a class that includes an array? - c++

I have a C++ class with a static data member which is a constant. I added an array to the class definition, and now I get an error when trying to initialize the static member.
Here is the code:
class MyClass
{
int i1;
int i2;
int i3;
//bool b1[2];
//bool b2[2];
public:
//Constructors
MyClass();
MyClass(const int i1In, const int i2In, const int i3In
/*, const bool b1In[2], const bool b2In[2]*/
);
// Copy constructor
MyClass(const Input& rhs);
// Destructor
~MyClass();
// Assignment
MyClass& operator=(const MyClass& rhs);
// Operators
bool operator==(const MyClass& m2) const;
bool operator!=(const MyClass& m2) const;
MyClass& operator++(int/*serves no purpose, but must be included*/);
static const MyClass S;
};
const MyClass S = { 0, 0, 0 /*,{ false,false }, { false,false }*/ };
The above code compiles without error, and the value of S is as expected. However, when I change the class definition to add the arrays b1 and b2 (uncomment two places in the class defn and add two array initializers in the initialization of S), I get the error
"C2440: 'initializing': cannot convert from 'initializer list' to 'MyClass'
note: No constructor could take the source type, or constructor overload resolution was ambiguous".
What is the proper way to define a constant variable of type MyClass that has the indicated values?
Windows 7 Pro, Visual Studio 2015

Have the constructor take the array parameters by constant reference.
MyClass(/*...*/ const bool (&b1In)[2], const bool (&b2In)[2])
const MyClass MyClass::S(/*...*/ { false,false }, { false,false } );
The array-as-parameter syntax is really just a cleverly disguised pointer which is why that didn't work.
Also, your operator++(int) returns a reference. Because that is the post-increment operator, it should return by value.

Related

How can I override the << operator for a class without it being in its namespace? [duplicate]

Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).

C++ initializing const

I need to be able to initialize a const member inside the constructor, which counts up every time I create a new object. I was shown in school how its suppose to work, but I'm getting errors all the time. It's something to do with the copy constructor.
Here's the code and the compiler errors:
class kunde {
public:
kunde(string name, int alter);
kunde(const kunde& orig);
~kunde();
int GetAlter() const;
string GetName() const;
const int GetKnr() const;
private:
string name;
int alter;
const int knr;
static int cnt;
static int MaxKnr;
};
int kunde::cnt = 0;
int kunde::MaxKnr = 1000;
kunde::kunde(string name, int alter):knr(MaxKnr++) {
this->name = name;
this->alter = alter;
}
kunde::kunde(const kunde& orig):knr(MaxKnr++){
this->name = orig.name;
this->alter = orig.alter;
}
kunde::~kunde() {
}
int kunde::GetAlter() const {
return alter;
}
string kunde::GetName() const {
return name;
}
const int kunde::GetKnr() const {
return knr;
}
main.cpp: In function 'int main(int, char**)':
main.cpp:35:15: error: use of deleted function 'kunde& kunde::operator=(const kunde&)'
v[0] = v[1];
^
In file included from main.cpp:17:0:
kunde.h:19:7: note: 'kunde& kunde::operator=(const kunde&)' is implicitly deleted because the default definition would be ill-formed:
class kunde {
^~~~~
kunde.h:19:7: error: non-static const member 'const int kunde::knr', can't use default assignment operator
knr is suppose to be an account number. each time you create an object it creates a new const account number which stays.
As stated in comments, since knr is const, the compiler cannot generate a default copy-assignment operator= for the class, which is exactly what the compiler is complaining about for the v[0] = v[1]; statement:
note: 'kunde& kunde::operator=(const kunde&)' is implicitly deleted because the default definition would be ill-formed
const members cannot be re-assigned once initialized, thus cannot be copied.
The elements in a vector must be CopyAssignable and CopyConstructible (at least until C++11), but your class does not have a viable copy-assignment operator=, so it is not CopyAssignable (and it is not MoveAssignable in C++11 either, since a viable move-assignment operator= can't be generated, either).
The solution is to implement a copy-assignment operator= (and optionally a move-assignment operator=) that ignores knr, eg:
class kunde {
public:
kunde(string name, int alter);
kunde(const kunde& orig);
kunde(kunde&& orig);
...
kunde& operator=(const kunde& rhs);
kunde& operator=(kunde&& rhs);
...
private:
string name;
int alter;
const int knr;
...
};
kunde::kunde(string name, int alter)
: knr(MaxKnr++), name(name), alter(alter)
{
}
kunde::kunde(const kunde& orig)
: knr(MaxKnr++), name(orig.name), alter(orig.alter)
{
}
kunde::kunde(kunde&& orig)
: knr(MaxKnr++), name(std::move(orig.name)), alter(orig.alter)
{
}
kunde& kunde::operator=(const kunde& rhs)
{
if (&rhs != this)
{
name = rhs.name;
alter = rhs.alter;
// CAN'T BE DONE, SO IGNORE IT
// knr = rhs.knr;
}
return *this;
}
kunde& kunde::operator=(kunde&& rhs)
{
name = std::move(rhs.name);
alter = rhs.alter;
// CAN'T BE DONE, SO IGNORE IT
// knr = rhs.knr;
return *this;
}

Callback function: Incompatible argument

I am trying to use callback function in my problem but I got into some troubles. In the sort() function, the parameter &compareType has an error:
Argument of type "bool (Person::*)(const Person& p1, const Person& p2)" is incompatible with parameter of type "compare"`
person.h
class Person
{
public:
bool compareType(const Person& p1, const Person& p2) { return ... };
void sort()
{
...
list->addInOrder(person, &compareType);
...
}
...
}
dlinkedlist.h
typedef bool (*compare)(const Person& p1, const Person&p2);
class dlinkedlist
{
public:
void addInOrder(const Person& person, compare comparefunc)
{
Person person2;
...
comparefunc(person, person2);
...
}
}
bool compareType(const Person& p1, const Person& p2)
is actually of type
bool (Person::*) (const Person&, const Person&)
You have to make your method static to have correct type.
There are mainly three solutions.
You can either:
declare the member method as static
define a function outside the class that is friend of your class (if needed) and use it
The third solution is maybe the most interesting one:
you can use a non-capturing lambda function that, because of the fact that is a non-capturing one, can decay to a pointer to function.
So, as an example, the following lambda is perfectly fine in your case:
[](const Person& p1, const Person& p2) { return true; }
It follows a minimal, working example:
struct A { };
using Fn = bool(*)(const A &, const A &);
void f(Fn fn) {
fn(A{}, A{});
};
int main() {
f([](const A &, const A &){ return true; });
};
As you can see, the lambda automatically decays to a pointer to function, so it's fine to use it in such a case.
Obviously, the solution involving the lambda is not suitable if you need to access private members, of course.
A non-static method is different to a free function or static method. You can see that from the type in the error message:
bool (Person::*)(const Person& p1, const Person& p2)
which is different from the type of a simple function
bool (*)(const Person& p1, const Person& p2)
(intuitively, the non-static method has to somehow get a this pointer, so the compiler has to do something different when calling it).
Note that your compareType shouldn't be a non-static member anyway - you'd have to call it like
personA.compareType(personB, personC)
which doesn't make much sense.
Either make it a static method (so you don't invoke it on an instance of Person)
class Person {
public:
static bool compareType(const Person&, const Person&);
// ...
};
or just make it a free function
bool comparePeople(const Person&, const Person&);
Non static class method implicitly adds reference to this, so your function actually looks like
bool compareType(Person *this, const Person &p1, const Person &p2);
You should declare it as static, and this will not be passed into.

operator overloading c++

I am trying to preform operator overloading in C++;
for some reason the compiles keeps on giving me the error
error: ‘bool Matrix::operator==(const Matrix&, const Matrix&)’ must take exactly one argument
Now, I know that there is some way to to it with one argument using this, but I understood that by using friend I can do it this way, but it still is not working.
Here is my code,
Thanks in advance.
class Matrix{
public:
Matrix();
friend bool operator==(Matrix &mtrx1,Matrix &mtrx2);
friend bool operator!=(Matrix &mtrx1,Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool Matrix::operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
}
The operator== member function is declared as:
class foo {
public:
bool operator==( foo const & rhs ) const;
};
The operator== global function is declared as:
bool operator==( foo const & lhs, foo const & rhs );
Generally, the member function is declared and defined first. Then, the global function is defined in terms of the member function as
Only one between the member function and global function is declared and defined. Having both of them is ambiguous for statements like (1) in the following
foo f1;
foo f2;
bool f1EqualsF2 = (f1 == f2 ); // (1), ambiguous
and in such cases compiler returns error. In g++, the error message looks like
equals.cpp:24: error: ambiguous overload for ‘operator==’ in ‘f1 == f2’
equals.cpp:8: note: candidates are: bool foo::operator==(const foo&) const
equals.cpp:17: note: bool operator==(const foo&, const foo&)
Whenever operator== is done, its recommended to do the corresponding operator!=.
Although you've put the friend declaration inside the class, it's not a member. So the function definition should be a non-member:
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2) {...}
You also need to add const qualifiers to the arguments of the declarations, to match those in the definition.
class Matrix{
public:
Matrix();
friend bool operator==(const Matrix &mtrx1, const Matrix &mtrx2);
friend bool operator!=(const Matrix &mtrx1, const Matrix &mtrx2);
protected:
std::vector<Cell> _matrix;
int _row;
int _col;
};
inline bool operator==(const Matrix& mtrx1, const Matrix& mtrx2){
/* .......... */
return true;
}
Pass compilation in Visual Studio 2005.
omit the const qualifier in your friend declaration
don't need Matrix:: in operation== definition
You do it with 2 parameters if you are doing it outside of the class, not as a member function.
As a member function you need only 1 parameter (the other parameter is *this)

difference between global operator and member operator

Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).