I am trying to pass a STL container in a class to another class
For ex.
typedef std::map<std::string, int*> Container_t;
class A
{
public:
const Container_t * get_container() const;
private:
Container_t container;
};
const Container_t * A::get_container() const
{
return &container;
}
And when I try to get this in another class, I get compilation error
saying
error: argument of type ‘Container_t* (A::)()const’ does not match ‘Container_t*’
void foo(A * a)
{
const Container_t * container = a->get_container();
}
It will be best if I can get const reference instead of pointer. but I don't want to copy the return value of function in A. So it has to be either pointer or reference. Thank you
You need to change your function signature to:
const Container_t * get_container() const;
The reason is that the last const there at the end says "calling this function and using what it returns will not change this object." However, returning a (non-const) pointer to the member variable gives the caller freedom to change that variable, so you have to return a const Container_t * to ensure that the caller doesn't modify the member variable (and thereby modify the object).
Related
I am doing an assignment for a C++ class and I am getting an error when using push back with vector. I honestly cannot find any info on why this isnt working and giving me a "no instance of overloaded function" error
class StudentData {
class StudyModule {
private:
const int studyModuleCode;
const std::string studyModuleName;
public:
StudyModule();
StudyModule(const StudyModule& copy);
~StudyModule();
};
private:
const int studentNumber;
std::string studentName;
std::vector<StudyModule*> modules;
public:
StudentData();
StudentData(const StudentData& copy);
~StudentData();
void addModules(const StudyModule& module);
int howManyModules();
};
void StudentData::addModules(const StudyModule& module)
{
this->modules.push_back(&module);
}
The function addModules() is declared like this:
void addModules(const StudyModule& module);
that is, its parameter is a reference to const object.
But the vector has a pointer to a non-const object as its template argument:
std::vector<StudyModule*> modules;
Thus, the compiler issues a message for this statement:
this->modules.push_back(&module);
because the expression &module has the type const StudyModule *, ie a pointer to a const object.
Even if you would change the template argument of the vector like this:
std::vector<const StudyModule *> modules;
your approach will be unsafe, because the user can pass a temporary object of type StudyModule to the function. In this case, storing a pointer to this object in the vector will become invalid when the temporary object is destroyed afterwards.
I have a class that can take both a non-const pointer or a const pointer as arguments to its overloaded constructors. In my particular case, I need to instantiate an object of this class from both const and non-const methods of class T, but it fails from const methods, as it can't assign the const pointer to foo .
myClass() {
public:
myClass(T* v);
myClass(const T* v);
// ...
T* foo;
// ...
}
Is it possible to assign the argument in both constructors to foo? If so, what would be the correct syntax?
EDIT:
In a more specific case, I have a class myClass that wraps around std::vector and allows to me to directly access subsets of a vector through a nested class mySubset:
template<typename _type>
myClass() {
std::vector<_type> data;
public:
class mySubset(){
myClass<type>* foo;
public:
mySubset(myClass<_type>* _in) { foo = _in; };
mySubset(const myClass<_type>* _in) { foo = _in; /* error */ };
// ...
}
// ...
myClass();
// ...
void mySubset method() { return mySubset(this); };;
void mySubset const_method const() { return mySubset(this); /* error */ };
// ...
}
The code within is irrelevant -basically mySubset allows to both read and write to specific vector positions. While I'm able to achieve what I want with separate const and non-const nested classes, I was looking for a way to do this with a single return type.
I think you'll have to reconsider your design since you can't initialize a T* with a const T* lvalue, without const_cast which should be avoided unless you're really really sure, (since it invokes an undefined behavior if you try to modify a const pointer after casting away its constness)
Instead, you could use template type deduction for const and non const
template <typename T>
class myClass {
public:
//myClass(T* v):foo(v) { }
myClass( T* v):foo(v)
{
}
// ...
T* foo;
// ...
};
Then,
int a =42;
const int* p1 = &a;
int *p2 = &a;
myClass X1(p1); //C++17 auto type deduction or use myClass<const int> X1(p1)
myClass X2(p2);
You could using const_cast in your const T* constructor, but typically you shouldn't.
const T* means "point to a constant value T", and you store a "pointer to a T". If you do a const cast, you could end up modifying a value which shouldn't be modified. If you aren't going to modify foo, just declare it const T* and just use the single const T* constructor.
I'd check to see if this is a design issue. A lot of the times these scenarios appear:
(1) Where you're storing a pointer to something as non-const when it should be const. Typically this is because you're accessing values in another object and you should be passing the object as a (possibly const) reference at each use site rather than storing a pointer to it.
(2) When you really want to store a copy of an object, in which case you just keep a regular T and pass it in as const T& in the constructor.
(3) You're dealing with raw C-style strings and want to copy the contents into your own buffer.
If you don't want to use parameterized-type (template) class as #P0W's answer, it is not possible you can use only one pointer to accept all constant and non-constant pointer type. You need another constant pointer type to accept only const <your another class> * in your wrapper class.
Below code works after you have two separate pointer types in wrapper class which you may not like.
#include <iostream>
using namespace std;
class SomeObject {
public:
SomeObject(){}
explicit SomeObject(int i):testVal(i){}
private:
int testVal;
};
class PtWrapper {
public:
PtWrapper(SomeObject *pso);
PtWrapper(const SomeObject *cpso);
private:
SomeObject *pSO;
const SomeObject *cpSO;
};
int main(int argc, char *argv[]) {
SomeObject so(133);
SomeObject *pso = &so;
const SomeObject cso(166);
const SomeObject *cpso = &cso;
PtWrapper pw1(pso);
PtWrapper pw2(cpso);
return 0;
}
PtWrapper::PtWrapper(SomeObject *pso) :pSO(pso){
}
PtWrapper::PtWrapper(const SomeObject *cpso):cpSO(cpso){}
I'm developing a class that must return an iterator with the begin() method. Also, I have to develop a function that receives a const reference of this class and iterates over it.
When I try to get an iterator from this method, I have the following compilation error: "the object has type qualifiers that are not compatible with the member function."I can't understand why this error appears.
Here is the code that I have written:
// ------------ class Neuron -------------
class Neuron { ... };
// ---------------------------------
// ------------ class AbstractLayer -------------
class AbstractLayer {
public:
class Iterator : public std::iterator<std::input_iterator_tag, Neuron> {
public:
Iterator(Neuron *neurons) : _neurons(neurons) {}
private:
Neuron *_neurons;
};
virtual Iterator begin() = 0;
virtual const Iterator begin2() = 0;
};
// ----------------------------------------
// ------------ class Layer -------------
class Layer : AbstractLayer {
public:
Layer(){};
Iterator begin(){ return Iterator(_neurons); }
const Iterator begin2(){ return (const Iterator)begin(); }
private:
Neuron *_neurons;
int _size;
};
// --------------------------------
// ------------ Method where the problem is -------------------
void method(const AbstractLayer &layer){
// Error in both methods:
// "the object has type qualifiers that are not compatible with the member function."
layer.begin();
layer.begin2();
}
// -------------------------------------------------------------
In the method function, layer references a constant object. That means you can only call functions marked as const. Like e.g.
class AbstractLayer {
public:
...
virtual const Iterator begin() const = 0; // <- Note use of `const` here
...
};
You do not need begin and begin2. What you need is two versions of begin - const and non-const. A const one would return const iterator. You also might want a cbegin (const only) which would always return const iterator.
In method, the layer argument is const which prevents you from calling non-const methods on it. If you take layer by non-const reference (void method(AbstractLayer &layer)), you will be able to call both methods.
You should probably provide a const begin method that returns a const_iterator so you can iterate over a const AbstractLayer.
Your function accepts a const AbstractLayer which means that only const member functions can be called on it. However, begin and begin2 are not const. In fact, given that only begin2 returns a const Iterator, it wouldn't make sense to try and call begin anyway in this method.
Change
virtual const Iterator begin2() = 0;
to
virtual const Iterator begin2() const = 0;
and
const Iterator begin2()
to
const Iterator begin2() const
Finally, returning a const Iterator is actually meaningless in your code, as the const is discarded on account of an rvalue being returned. Regardless, you shouldn't need to perform casting to const Iterator when you call begin; just return an Iterator and the compiler will take care to make it const.
Finally, your Layer class needs to derive publicly from AbstractLayer:
class Layer : public AbstractLayer
Live Demo
In the examlpe below I need to define a function to compare my objects using certain rules in getHappiness(Animal*) method. The method cannot be static and rather complicated. I need a pointer in the comparison definition to call getHappiness method.
So my question is: how do I pass a pointer to this method, it gets called automatically when I insert an element into the map. And also it doesn't seem that I can instantiate Compare structure and pass the pointer to the constructor.
Am I doing anything wrong? Maybe there is an alternative way to how I define a comparison function?
struct Compare {bool operator()(Animal* const, Animal* const) const;};
bool
Compare::operator()(Animal* const a1, Animal* const a2) const {
Zoo* zoo; // somehow I need to get access to the Zoo instance here
if (zoo->getHappiness(a1) > zoo->getHappiness(a2)) return true;
return false;
}
Class Zoo(){
std::multimap<Animal*, Man*, Compare> map;
int getHappiness(Animal*); // cannot be static
}
int main(){
...
Zoo zoo;
zoo.map.insert(...);
...
}
There is a design issue in your code. Happiness should be an attribute which belong to an animal not a zoo. So implement getHappiness() on animal makes your code much simpler:
struct Compare
{
bool operator()(Animal& const, Animal& const) const;
};
bool Compare::operator()(Animal& const a1, Animal& const a2) const
{
return a1.getHappiness() < a2.getHappiness();
}
Class Zoo(){
std::multimap<Animal, Man, Compare> map;
}
Also, if not necessary, don't use pointer. If you can't avoid pointer, use smart pointer in STL container.
I'm trying to understand better how does const-correctness work and more specifically, when dealing with classes whose members are based on containers and smart pointers.
I guess that the const-correctness property is the same regardless of the class members. However, since I'm having some difficulties to clearly understand what's going on,
I decided to ask you for advice.
So, here is the context. I've a ShapeContainer class that has as private class member a vector of smart pointers.
The Shape class is abstract and has the following virtual function virtual float doSomething(); which is then redefined by its derived classes. Note that it's a non-const class function.
The relevant part of the code is given below:
class ShapeContainer{
public:
typedef std::shared_ptr<Shape> ShapePtr;
typedef std::vector<ShapePtr> ShapePtrContainer;
// .......
const ShapePtr & operator[]( int ) const { return m_vect[index]; }; // const version
// ShapePtr & operator[]( int ) { return m_vect[index]; }; // non-const version
// .......
private:
ShapePtrContainer m_vect;
};
class Shape{
public:
// ...
virtual float doSomething() = 0;
};
Here are my questions.
Q1. Why do I'm allowed to call the doSomething() function in the following way: int index = 0; float tmp = container1[index]->doSomething(); (having ShapeContainer container1=createBasicShapes();)?
From what I understand, after calling to the const ShapePtr operator[] const function we'll get a const pointer to a Shape object, however the doSomething() virtual
function is not const. So, how does a reference to a const-object can call a non-const function?
Q2. By calling the doSomething() function as previouly ilustrated (float tmp =container1[index]->doSomething();) and by adding a non-const version of the operator[], this latter
overloaded version is then called instead of the const-version one. Why does it is so?
Now, instead of having a ShapeContainer class, I've now a new class named ShapeContainerInfo that still has a vector but of an intermediate ShapeInfo class (that has a smart pointer as a class member).
class ShapeContainerInfo{
public:
typedef std::vector<ShapeInfo> ShapeContainer;
const ShapeInfo & operator []( int index) const { return m_vect[index]; };
// ShapeInfo & operator []( int index) { return m_vect[index]; }; // non-const version
private:
ShapeContainer m_vect;
};
class ShapeInfo{
public:
typedef std::shared_ptr<Shape> ShapePtr;
// ...
float doSomething(){ return m_ShapePtr->doSomething(); };
private:
ShapePtr m_ShapePtr;
int m_nID;
};
Q3. When I call float tmp = container2[i].doSomething();, I get the following compiler error: error C2662: 'ShapeInfo::doSomething' : cannot convert 'this' pointer from 'const ShapeInfo' to 'ShapeInfo &'.
However, when I add a non-const vesion of the overloaded operator [] the compiler error is gone. So, why do I really need the non-const operator[] for ShapeContainerInfo and not for ShapeContainer?
Q4. If the m_vect private member of ShapeContainerInfo is set now as public member and only the const-version of operator[] is defined (not the non-const one), there are no compiler error messages. Why this? e.g. after setting m_vect to be a public class member: float tmp = info.m_vect[i].doSomething();
Q5. How could I correctly define both the ShapeInfo and ShapeContainerInfo classes such that I only need to define the const-version of the operator[] and still being able to call the float doSomething() function?
For those of you interested in the whole sample code, please find it here.
Clarifications, suggestions are always welcomed :-)
Merci!
Q1: The shared_ptr is const, that doesn't mean that the pointed to object is const. For that you would want shared_ptr<const Shape>.
Q2: Since you're ShapeContainer was not const, the non-const function was a better match, so it was called instead of the const version.
Q3: vector propagates its constness to its elements. shared_ptr does not. This is inline with the behavior of arrays and raw pointers. The elements of const arrays are const. The thing pointed to by a const pointer is not (necessarily) const.
Q4: Are you saying this produces no error?
ShapeContainerInfo info;
info[0].doSomething();
Please clarify, because that should be an error.
Q4: Okay, so you're saying that this produces no error:
ShapeContainerInfo info;
info.m_vect[0].doSomething();
Nor should it. The vector is not const. It's only inside the const member function that the vector(and all other members) are treated as const.
Q5: Make m_vect a vector of unique pointers. Inside the const function, the vector itself will be const, and the unique pointers will be const. But the objects that the unique pointers point to will be mutable.
As an example, the set function in this class is not legal:
struct Foo
{
void set(int index, int value) const
{
v[index] = value;
}
std::vector<int> v;
};
But this one is:
struct Foo
{
void set(int index, int value) const
{
*v[index] = value;
}
std::vector<std::unique_ptr<int>> v;
};