#include "booking.h"
#include <iostream>
booking::booking ( const std::string p_title, const std::string p_notice, const category p_category, const person p_person, const booking::Type p_type, const double p_value ) :
m_type{ p_type },
m_title{ p_title },
m_notice{ p_notice },
m_person{ p_person },
m_category{ p_category },
m_value { p_value }
{
std::cout << "Booking was created" << std::endl; // Debug Message
}
These are the files (everything thats necessary to know in my opinion)
#pragma once
#include <string>
#include "person.h"
#include "category.h"
class booking
{
public:
enum Type { TYPE_REVENUE, TYPE_EXPENDITURE };
booking ( const std::string p_title, const std::string p_notice, const category p_category, const person p_person, const booking::Type p_type, const double p_value ); //Basic Constructor
~booking();
Type GetType ( );
std::string GetTitle ( );
std::string GetNotice ( );
category GetCategory ( );
double GetValue ( );
private:
Type m_type;
std::string m_title;
std::string m_notice;
category m_category;
person m_person;
double m_value;
};
If i put one of the class members (like m_type or the double value, it doesnt matter which) to const, it throws following error:
Fehler 1 error C2280: booking &booking::operator =(const booking &) : attempting to reference a deleted function C:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2013 CTP\include\utility 53
I dont get why the compiler complains about the copy constructor and whats basicly the matter.
You can't (reasonably) assign to an object of a class that has const members.
That's why you get an error about the copy assignment operator.
You're not getting a complaint about the copy constructor.
In other news:
In C++ ALL UPPERCASE names are a convention for macros. If they're used for anything else (e.g. constants, as in Java) then you increase the risk of name collisions and inadvertent text replacement. Besides it's an eyesore, read by many as extra heavy emphasis. Java doesn't have a preprocessor. C++ does have one.
It's a good idea to pass non-basic-type arguments in general as reference to const (you only added const). There are some extra considerations for large arguments that are copied. In C++11 these are best passed by value and moved.
Simple "getter" member function should be declared const so that they can be called on a const object.
Regarding the Java-inspired Get prefixes, consider GetSin(u)+GetCos(v) versus sin(u)+cos(v). In Java a Get prefix can have some value for tools that use introspection. Java has introspection. C++ doesn't have instrospection. The conventions employed should better be adapted to the language used.
When you declare a const member, the compiler does not generate a default assignment operator (it has no clue what to do with this member during assignment, after all, it is const ?), you will have to write the assignment operator yourself.
Note:
pass you parameters by reference to const.
operator= is not the copy-constructor, it is the assignment operator.
const objects cannot be updated, so in your assignment operator you cannot modify the object.
If you don't declare your own assignment operator, the compiler generates one for you which does member-wise copy. But if there is a const member, this doesn't work, so it can't generate the assignment operator after all. (In C++11 this is called having a deleted assignment operator).
Finally, if you have some code that tries to use the assignment operator, then you get this error about attempting to use the deleted assignment operator. Some of the standard library containers or algorithms require the assignment operator to be present. You didn't show all your code but somewhere you will have tried to perform an operation that requires assignment.
referring this thread, as to the copy constructor with const members,
the general form of the copy constructor is,
class Foo {
Foo( const Foo& f ) :
mem1( f.mem1 ), mem2( f.mem2 ) /* etc */
{}
};
where mem1 and mem2 are data members of Foo, which can be const
members, non-const members, const references or non-const references.
Related
#include "booking.h"
#include <iostream>
booking::booking ( const std::string p_title, const std::string p_notice, const category p_category, const person p_person, const booking::Type p_type, const double p_value ) :
m_type{ p_type },
m_title{ p_title },
m_notice{ p_notice },
m_person{ p_person },
m_category{ p_category },
m_value { p_value }
{
std::cout << "Booking was created" << std::endl; // Debug Message
}
These are the files (everything thats necessary to know in my opinion)
#pragma once
#include <string>
#include "person.h"
#include "category.h"
class booking
{
public:
enum Type { TYPE_REVENUE, TYPE_EXPENDITURE };
booking ( const std::string p_title, const std::string p_notice, const category p_category, const person p_person, const booking::Type p_type, const double p_value ); //Basic Constructor
~booking();
Type GetType ( );
std::string GetTitle ( );
std::string GetNotice ( );
category GetCategory ( );
double GetValue ( );
private:
Type m_type;
std::string m_title;
std::string m_notice;
category m_category;
person m_person;
double m_value;
};
If i put one of the class members (like m_type or the double value, it doesnt matter which) to const, it throws following error:
Fehler 1 error C2280: booking &booking::operator =(const booking &) : attempting to reference a deleted function C:\Program Files (x86)\Microsoft Visual C++ Compiler Nov 2013 CTP\include\utility 53
I dont get why the compiler complains about the copy constructor and whats basicly the matter.
You can't (reasonably) assign to an object of a class that has const members.
That's why you get an error about the copy assignment operator.
You're not getting a complaint about the copy constructor.
In other news:
In C++ ALL UPPERCASE names are a convention for macros. If they're used for anything else (e.g. constants, as in Java) then you increase the risk of name collisions and inadvertent text replacement. Besides it's an eyesore, read by many as extra heavy emphasis. Java doesn't have a preprocessor. C++ does have one.
It's a good idea to pass non-basic-type arguments in general as reference to const (you only added const). There are some extra considerations for large arguments that are copied. In C++11 these are best passed by value and moved.
Simple "getter" member function should be declared const so that they can be called on a const object.
Regarding the Java-inspired Get prefixes, consider GetSin(u)+GetCos(v) versus sin(u)+cos(v). In Java a Get prefix can have some value for tools that use introspection. Java has introspection. C++ doesn't have instrospection. The conventions employed should better be adapted to the language used.
When you declare a const member, the compiler does not generate a default assignment operator (it has no clue what to do with this member during assignment, after all, it is const ?), you will have to write the assignment operator yourself.
Note:
pass you parameters by reference to const.
operator= is not the copy-constructor, it is the assignment operator.
const objects cannot be updated, so in your assignment operator you cannot modify the object.
If you don't declare your own assignment operator, the compiler generates one for you which does member-wise copy. But if there is a const member, this doesn't work, so it can't generate the assignment operator after all. (In C++11 this is called having a deleted assignment operator).
Finally, if you have some code that tries to use the assignment operator, then you get this error about attempting to use the deleted assignment operator. Some of the standard library containers or algorithms require the assignment operator to be present. You didn't show all your code but somewhere you will have tried to perform an operation that requires assignment.
referring this thread, as to the copy constructor with const members,
the general form of the copy constructor is,
class Foo {
Foo( const Foo& f ) :
mem1( f.mem1 ), mem2( f.mem2 ) /* etc */
{}
};
where mem1 and mem2 are data members of Foo, which can be const
members, non-const members, const references or non-const references.
I'm taking a class on object oriented programming using C++.
In our text it says,
If we do not declare a copy constructor, the compiler inserts code
that implements a shallow copy. If we do not declare an assignment
operator, the compiler inserts code that implements a shallow
assignment.
What I want to know, is whether this is in fact true, what the alluded to compiler mechanism is actually called, and how it works.
This is not a question about copy constructors, it is about compiler behavior.
EDIT> More context
Copy Constructor as defined by the text:
The definition of a copy constructor contains logic that
performs a shallow copy on all of the non-resource instance variables
allocates memory for each new resource
copies data from the source resource(s) to the newly created resource(s)
Resource as defined by the text
Memory that an object allocates at run-time represents a resource of that
object's class.
The management of this resource requires additional logic that was unnecessary for simpler classes that do not access resources. This additional logic
ensures proper handling of the resource and is often called deep copying and
assignment.
It's more accurate to say that the compiler defines a default copy constructor and a default copy assignment operator. These will copy/construct the new object by simply calling the copy constructor for all of the member variables.
For primitives like ints and floats, this usually isn't a problem.
For pointers, though. This is bad news! What happens when the first object deletes that pointer? Now the other object's pointer is invalid!
If a member variable cannot be copied (perhaps you used a std::unique_ptr to fix the above problem), then the default copy assignment/ctor won't work. How can you copy something that can't be copied? This will lead to a compiler error.
If you define your own copy constructor/assignment operator, you can make a "deep copy" instead. You can:
Create a new object, rather than copying the pointer
Explicitly "shallow copy" a pointer
Mix the above two based on what you actually want!
Initialize member variables with default/custom values in copied objects rather than copy whatever was in the original object.
Disable copying altogether
On and on and on
As you can see, there are plenty of reasons why you'd want to implement (or explicitly prohibit) your own copy assignment operator, copy constructor, their move counterparts, and destructor. In fact, there's a well-known C++ idiom known as The Rule of Five (formerly the Rule of 3) that can guide your decision on when to do this.
Yes it's true, and it's indeed called shallow copying. As for how it works, lets say you have a pointer variable, and you assign it to another pointer variable. This only copies the pointer and not what it points to, this is a shallow copy. A deep copy would have created a new pointer, and copied the actual contents that the first pointer points to.
Something like this:
int* a = new int[10];
// Shallow copying
int* b = a; // Only copies the pointer a, not what it points to
// Deep copying
int* c = new int[10];
std::copy(a, a + 10, c); // Copies the contents pointed to by a
The problem with shallow copying in regards to pointers should be quite obvious: After the initialization of b in the above example, you have two pointers both pointing to the same memory. If one then does delete[] a; then both pointers become invalid. If the two pointers are in different objects of some class, then there is no real connection between the pointers, and the second object won't know if the first object have deleted its memory.
The code for shallow copy is a simple assignment for every field. If:
class S {
T f;
};
S s1, s2;
A assignment like s1=s2; is equivalent to what happens in the following:
class S {
T f;
public:
S &operator=(const S&s) {
this->f = s.f; // and such for every field, whatever T is
}
};
S s1, s2;
s1=s2;
This is stated in 12.8-8 of the draft standard:
The implicitly-declared copy constructor for a class X will have the
form X::X(const X&) if
— each direct or virtual base class B of X has
a copy constructor whose first parameter is of type const B& or const
volatile B&, and
— for all the non-static data members of X that are
of a class type M (or array thereof), each such class type has a copy
constructor whose first parameter is of type const M& or const
volatile M&.123
Otherwise, the implicitly-declared copy constructor
will have the form X::X(X&)
12.8-28 says:
The implicitly-defined copy/move assignment operator for a non-union
class X performs memberwise copy/move assignment of its subobjects. [...] in the order in which they were declared in the class definition.
I'll use a basic class to define the behavior of the compiler as best as I know how to.
class Student sealed {
private:
std::string m_strFirstName;
std::string m_strLastName;
std::vector<unsigned short> m_vClassNumbers;
std::vector<std::string> m_vTeachers;
std::vector<unsigned short> m_vClassGrades;
public:
Student( const std::string& strFirstName, const std::string& strLastName );
std::string getFirstName() const;
std::string getLastName() const;
void setClassRoster( std::vector<unsigned short>& vClassNumbers );
std::vector<unsigned short>& getClassRoster() const;
void setClassTeachers( std::vector<std::string>& vTeachers );
std::vector<std::string>& getClassTeachers() const;
void setClassGrades( std::vector<unsigned short>& vGrades );
std::vector<unsigned short>& getGrades() const;
// Notice That These Are Both Commented Out So The Compiler Will
// Define These By Default. And These Will Make Shallow / Stack Copy
// Student( const Student& c ); // Default Defined
// Student& operator=( const Student& c ); // Default Defined
};
The version of this class with its declaration by default will construct both a copy constructor and an equal operator.
class Student sealed {
private:
std::string m_strFirstName;
std::string m_strLastName;
std::vector<unsigned short> m_vClassNumbers;
std::vector<std::string> m_vTeachers;
std::vector<unsigned short> m_vClassGrades;
public:
Student( const std::string& strFirstName, const std::string& strLastName );
std::string getFirstName() const;
std::string getLastName() const;
void setClassRoster( std::vector<unsigned short>& vClassNumbers );
std::vector<unsigned short>& getClassRoster() const;
void setClassTeachers( std::vector<std::string>& vTeachers );
std::vector<std::string>& getClassTeachers() const;
void setClassGrades( std::vector<unsigned short>& vGrades );
std::vector<unsigned short>& getGrades() const;
private:
// These Are Not Commented Out But Are Defined In The Private Section
// These Are Not Accessible So The Compiler Will No Define Them
Student( const Student& c ); // Not Implemented
Student& operator=( const Student& c ); // Not Implemented
};
Where the second version of this class will not since I declared both of them as being private!
This is probably the best way I can demonstrate this. I only showed the header file interface to this class since the c++ source or code to be compiled is not of a concern. The difference in how these two are defined during the Pre-Compile Stage dictates how the Compiler Will Work before it begins to compile the source code into object code.
Keep in mind though that the standard library strings & containers do implement their own Copy Constructor & Assignment Operators! But the same concept applies to the behavior of the compiler if a class has basic types such as int, float, double, etc. So the compiler will treat a Simple class in the same manner according to its declaration.
class Foo {
private:
int m_idx;
float m_fValue;
public:
explicit Foo( float fValue );
// Foo( const Foo& c ); // Default Copy Constructor
// Foo& operator=( const Foo& c ); // Default Assignment Operator
};
Second Version
class Foo {
private:
int m_idx;
float m_fValue;
public:
explicit Foo( float fValue );
private:
Foo( const Foo& c ); // Not Implemented
Foo& operator=( const Foo& c ); // Not Implemented
};
The compiler will treat this class in the same manner; it will not define either of these since they will not be implemented due to being declared as private.
I understand, or at least have an Idea of, why the following code does not work:
class Spambar {
public:
Spambar() {};
Spambar(Spambar& sb) {};
Spambar operator + (Spambar sb) {
Spambar new_sb;
return new_sb;
}
};
int main() {
Spambar sb1;
Spambar sb2;
Spambar sb3 = sb1 + sb2; // <<< Error: "No matching function for call to ... "
}
I guess, the problem is that the copy-constructor expects a reference to a Spambar instance. As no reference but a shallow instance is returned, the compilation fails.
So, how do I get that to work?
The problem is that the result of sb1 + sb2 is a temporary; the copy constructor used to initialise sb3 requires a non-const reference; and you can't take a non-const reference to a temporary.
You almost certainly want to fix this by changing the constructor's parameter type to Spambar const &. While you're at it, you should almost certainly do the same to operator+, and also make the operator itself const:
Spambar(Spambar const &);
Spambar operator + (Spambar const &) const;
If you're doing something very strange, and actually want the copy-constructor to modify its argument, then you'll have to either avoid passing temporaries to it, or do some nasty hackery with mutable or const_cast. In C++11, you would use a move constructor, with parameter type Spambar &&, for this sort of thing.
Your class does not have a copy constructor taking a const reference. Normally, a copy constructor looks like:
Spambar(const Spambar&);
The form you show is used in only very rare circumstances, and it is probably preventing your code from working.
It is an open ended question.
Effective C++. Item 3. Use const whenever possible. Really?
I would like to make anything which doesn't change during the objects lifetime const. But const comes with it own troubles. If a class has any const member, the compiler generated assignment operator is disabled. Without an assignment operator a class won't work with STL. If you want to provide your own assignment operator, const_cast is required. That means more hustle and more room for error. How often you use const class members?
EDIT: As a rule, I strive for const correctness because I do a lot of multithreading. I rarely need to implemented copy control for my classes and never code delete (unless it is absolutely necessary). I feel that the current state of affairs with const contradicts my coding style. Const forces me to implement assignment operator even though I don't need one. Even without const_cast assignment is a hassle. You need to make sure that all const members compare equal and then manually copy all non-const member.
Code. Hope it will clarify what I mean. The class you see below won't work with STL. You need to implement an assignment for it, even though you don't need one.
class Multiply {
public:
Multiply(double coef) : coef_(coef) {}
double operator()(double x) const {
return coef_*x;
}
private:
const double coef_;
};
You said yourself that you make const "anything which doesn't change during the objects lifetime". Yet you complain about the implicitly declared assignment operator getting disabled. But implicitly declared assignment operator does change the contents of the member in question! It is perfectly logical (according to your own logic) that it is getting disabled. Either that, or you shouldn't be declaring that member const.
Also, providing you own assignment operator does not require a const_cast. Why? Are you trying to assign to the member you declared const inside your assignment operator? If so, why did you declare it const then?
In other words, provide a more meaningful description of the problems you are running into. The one you provided so far is self-contradictory in the most obvious manner.
As AndreyT pointed out, under these circumstances assignment (mostly) doesn't make a lot of sense. The problem is that vector (for one example) is kind of an exception to that rule.
Logically, you copy an object into the vector, and sometime later you get back another copy of the original object. From a purely logical viewpoint, there's no assignment involved. The problem is that vector requires that the object be assignable anyway (actually, all C++ containers do). It's basically making an implementation detail (that somewhere in its code, it might assign the objects instead of copying them) part of the interface.
There is no simple cure for this. Even defining your own assignment operator and using const_cast doesn't really fix the problem. It's perfectly safe to use const_cast when you get a const pointer or reference to an object that you know isn't actually defined to be const. In this case, however, the variable itself is defined to be const -- attempting to cast away the constness and assign to it gives undefined behavior. In reality, it'll almost always work anyway (as long as it's not static const with an initializer that's known at compile time), but there's no guarantee of it.
C++ 11 and newer add a few new twists to this situation. In particular, objects no longer need to be assignable to be stored in a vector (or other collections). It's sufficient that they be movable. That doesn't help in this particular case (it's no easier to move a const object than it is to assign it) but does make life substantially easier in some other cases (i.e., there are certainly types that are movable but not assignable/copyable).
In this case, you could use a move rather than a copy by adding a level of indirection. If your create an "outer" and an "inner" object, with the const member in the inner object, and the outer object just containing a pointer to the inner:
struct outer {
struct inner {
const double coeff;
};
inner *i;
};
...then when we create an instance of outer, we define an inner object to hold the const data. When we need to do an assignment, we do a typical move assignment: copy the pointer from the old object to the new one, and (probably) set the pointer in the old object to a nullptr, so when it's destroyed, it won't try to destroy the inner object.
If you wanted to badly enough, you could use (sort of) the same technique in older versions of C++. You'd still use the outer/inner classes, but each assignment would allocate a whole new inner object, or you'd use something like a shared_ptr to let the outer instances share access to a single inner object, and clean it up when the last outer object is destroyed.
It doesn't make any real difference, but at least for the assignment used in managing a vector, you'd only have two references to an inner while the vector was resizing itself (resizing is why a vector requires assignable to start with).
I very rarely use them - the hassle is too great. Of course I always strive for const correctness when it comes to member functions, parameters or return types.
Errors at compile time are painful, but errors at runtime are deadly. Constructions using const might be a hassle to code, but it might help you find bugs before you implement them. I use consts whenever possible.
I try my best to follow the advice of using const whenever possible, however I agree that when it comes to class members, const is a big hassle.
I have found that I am very careful with const-correctness when it comes to parameters, but not as much with class members. Indeed, when I make class members const and it results in an error (due to using STL containers), the first thing I do is remove the const.
I'm wondering about your case... Everything below is but supposition because you did not provide the example code describing your problem, so...
The cause
I guess you have something like:
struct MyValue
{
int i ;
const int k ;
} ;
IIRC, the default assignment operator will do a member-by-member assignment, which is akin to :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
this->k = rhs.k ; // THIS WON'T WORK BECAUSE K IS CONST
return *this ;
} ;
Thus, this won't get generated.
So, your problem is that without this assignment operator, the STL containers won't accept your object.
As far I as see it:
The compiler is right to not generate this operator =
You should provide your own, because only you know exactly what you want
You solution
I'm afraid to understand what do you mean by const_cast.
My own solution to your problem would be to write the following user defined operator :
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
// DON'T COPY K. K IS CONST, SO IT SHOULD NO BE MODIFIED.
return *this ;
} ;
This way, if you'll have:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 2 }
As far as I see it, it is coherent. But I guess, reading the const_cast solution, that you want to have something more like:
MyValue a = { 1, 2 }, b = {10, 20} ;
a = b ; // a is now { 10, 20 } : K WAS COPIED
Which means the following code for operator =:
MyValue & operator = (const MyValue & rhs)
{
this->i = rhs.i ;
const_cast<int &>(this->k) = rhs.k ;
return *this ;
} ;
But, then, you wrote in your question:
I would like to make anything which doesn't change during the objects lifetime const
With what I supposed is your own const_cast solution, k changed during the object lifetime, which means that you contradict yourself because you need a member variable that doesn't change during the object lifetime unless you want it to change!
The solution
Accept the fact your member variable will change during the lifetime of its owner object, and remove the const.
you can store shared_ptr to your const objects in STL containers if you'd like to retain const members.
#include <iostream>
#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#include <vector>
class Fruit : boost::noncopyable
{
public:
Fruit(
const std::string& name
) :
_name( name )
{
}
void eat() const { std::cout << "eating " << _name << std::endl; }
private:
const std::string _name;
};
int
main()
{
typedef boost::shared_ptr<const Fruit> FruitPtr;
typedef std::vector<FruitPtr> FruitVector;
FruitVector fruits;
fruits.push_back( boost::make_shared<Fruit>("apple") );
fruits.push_back( boost::make_shared<Fruit>("banana") );
fruits.push_back( boost::make_shared<Fruit>("orange") );
fruits.push_back( boost::make_shared<Fruit>("pear") );
BOOST_FOREACH( const FruitPtr& fruit, fruits ) {
fruit->eat();
}
return 0;
}
though, as others have pointed out it's somewhat of a hassle and often easier in my opinion to remove the const qualified members if you desire the compiler generated copy constructor.
I only use const on reference or pointer class members. I use it to indicate that the target of the reference or pointer should not be changed. Using it on other kinds of class members is a big hassle as you found out.
The best places to use const is in function parameters, pointers and references of all kinds, constant integers and temporary convenience values.
An example of a temporary convenience variable would be:
char buf[256];
char * const buf_end = buf + sizeof(buf);
fill_buf(buf, buf_end);
const size_t len = strlen(buf);
That buf_end pointer should never point anywhere else so making it const is a good idea. The same idea with len. If the string inside buf never changes in the rest of the function then its len should not change either. If I could, I would even change buf to const after calling fill_buf, but C/C++ does not let you do that.
The point is that the poster wants const protection within his implementation but still wants the object assignable. The language does not support such semantics conveniently as constness of the member resides at the same logical level and is tightly coupled with assignability.
However, the pImpl idiom with a reference counted implementation or smart pointer will do exactly what the poster wants as assignability is then moved out of the implementation and up a level to the higher level object. The implementation object is only constructed/destructed whence assignment is never needed at the lower level.
I think your statement
If a class has const any member, the
compiler generated assignment operator
is disabled.
Might be incorrect. I have classes that have const method
bool is_error(void) const;
....
virtual std::string info(void) const;
....
that are also used with STLs. So perhaps your observation is compiler dependent or only applicable to the member variables?
I would only use const member iff the class itself is non-copyable. I have many classes that I declare with boost::noncopyable
class Foo : public boost::noncopyable {
const int x;
const int y;
}
However if you want to be very sneaky and cause yourself lots of potential
problems you can effect a copy construct without an assignment but you have to
be a bit careful.
#include <new>
#include <iostream>
struct Foo {
Foo(int x):x(x){}
const int x;
friend std::ostream & operator << (std::ostream & os, Foo const & f ){
os << f.x;
return os;
}
};
int main(int, char * a[]){
Foo foo(1);
Foo bar(2);
std::cout << foo << std::endl;
std::cout << bar<< std::endl;
new(&bar)Foo(foo);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
}
outputs
1
2
1
1
foo has been copied to bar using the placement new operator.
It isn't too hard. You shouldn't have any trouble making your own assignment operator. The const bits don't need to be assigned (as they're const).
Update
There is some misunderstanding about what const means. It means that it will not change, ever.
If an assignment is supposed to change it, then it isn't const.
If you just want to prevent others changing it, make it private and don't provide an update method.
End Update
class CTheta
{
public:
CTheta(int nVal)
: m_nVal(nVal), m_pi(3.142)
{
}
double GetPi() const { return m_pi; }
int GetVal() const { return m_nVal; }
CTheta &operator =(const CTheta &x)
{
if (this != &x)
{
m_nVal = x.GetVal();
}
return *this;
}
private:
int m_nVal;
const double m_pi;
};
bool operator < (const CTheta &lhs, const CTheta &rhs)
{
return lhs.GetVal() < rhs.GetVal();
}
int main()
{
std::vector<CTheta> v;
const size_t nMax(12);
for (size_t i=0; i<nMax; i++)
{
v.push_back(CTheta(::rand()));
}
std::sort(v.begin(), v.end());
std::vector<CTheta>::const_iterator itr;
for (itr=v.begin(); itr!=v.end(); ++itr)
{
std::cout << itr->GetVal() << " " << itr->GetPi() << std::endl;
}
return 0;
}
Philosophically speaking, it looks as safety-performance tradeoff. Const used for safety. As I understand, containers use assignment to reuse memory, i.e. for sake of performance. They would may use explicit destruction and placement new instead (and logicaly it is more correct), but assignment has a chance to be more efficient. I suppose, it is logically redundant requirement "to be assignable" (copy constructable is enough), but stl containers want to be faster and simpler.
Of course, it is possible to implement assignment as explicit destruction+placement new to avoid const_cast hack
Rather than declaring the data-member const, you can make the public surface of the class const, apart from the implicitly defined parts that make it (semi)regular.
class Multiply {
public:
Multiply(double coef) : coef(coef) {}
double operator()(double x) const {
return coef*x;
}
private:
double coef;
};
You basically never want to put a const member variable in a class. (Ditto with using references as members of a class.)
Constness is really intended for your program's control flow -- to prevent mutating objects at the wrong times in your code. So don't declare const member variables in your class's definition, rather make it all or nothing when you declare instances of the class.
I'd really like to be able to assign a std::string object from a DecoratedString object that I'm writing.
class DecoratedString
{
private:
std::string m_String;
public:
DecoratedString(const std::string& initvalue)
: m_String(initvalue)
{
}
const std::string& ToString() const
{
return m_String;
}
const std::string& operator=(const DecoratedString& rhs)
{
return rhs.ToString();
}
}
I've written a unit test to make sure this works:
void DecoratedStringTest::testAssignmentToString()
{
std::string expected("test");
DecoratedString sut(expected);
std::string actual;
actual = sut;
CPPUNIT_ASSERT_EQUAL(actual, sut.ToString());
}
However, the compiler says error: no match for 'operator=' in 'actual = sut'. It then lists the overloaded operator= options from the standard library.
Why isn't the compiler finding the operator= I defined?
EDIT:
So I guess I need a conversion operator, not an assignment operator. Huge thanks to the people that saw what I was trying to do and explained what I should do instead.
The operator = you have defined is for assigning decorated strings to other decorated strings and returning an std::string from that assignment.
What you want is a member "conversion operator" that automatically converts a decorated string to an std::string whenever required, like this:
operator std::string const &() const { return ToString(); }
That will also convert a decorated string automatically to a std::string const & whenever one is needed (i.e. when comparing to an std::string, or passing a DecoratedString to a function which takes a std::string const &).
The compiler is complaining about this line:
actual = sut;
which should be:
actual = sut.ToString();
Alternatively you should provide a cast operator to implicitly convert a DecoratedString to a std::string:
class DecoratedString
{
...
operator std::string() const
{
return ToString();
}
};
You're overloading the unary assignment operator that is intended for assigning a specific type to DecoratedString and is supposed to return a reference to DecoratedString so you can chain assignments. This operator is not designed to allow you to assign an object of DecoratedString to a different datatype, but rather so you can assign an object that isn't necessarily a DecoratedString to a DecoratedString. It also gives you a well-defined function to handle any sort of specific processing that an assignment of your class might required (deep copy, for example).
You either have to call your ToString() function or you'll have to create a conversion operator that can convert your DecoratedString into a std::string by implementing the following member function for DecoratedString:
operator std::string () const;
This might or might not be a good idea as this conversion operator will be used implicitly by the compiler and might lead to unexpected behaviour.
As an aside, another reason why your operator overload is not working is that you're trying to overload a function by its return value, which is a big no-no in C++.
You got it backwards. The operator= needs to be defined on the std::string to be able to accept your object, not the class you are assigning from, but since you are dealing with the standard library you can't do that.
An alternative would be a streaming operator (as a free function):
std::string& operator<<( std::string& out, const your_class& yc )
{
out.assign( yc.to_string());
return out;
}
your_class myobj;
std::string str;
str << myobj;
Or just define regular streaming for std::ostream and use std::stringstream.
Edit:
Yet another option, as others noted, is the type conversion operator:
your_class::operator const std::string() const;
Modern practice though tells us it's not the greatest idea (temporaries, extra copies, surprises).