ctors and consts

Hi -

I'm trying to build a ctor for a class. The ctor will invoke the ctor of a child class 10 times, establishing a different constant within each. If this worked correctly, the 10 child objects' constants would be 512, 256, 128, 64, 32, 16, 8, 4, 2 and 1.

Here's what I've tried:

1
2
3
4
5
ModPredist::ModPredist(int32_t rv)
{
    for (int i = 1; i <= 10; ++i)
        cells.push_back(ModPredistCell(i, rv));
}


and:

1
2
3
4
5
ModPredistCell::ModPredistCell(int i, int32_t rv)
    : PLANT(1024 / intexp(2, i))
{
    ...
}


I get this error message from the compiler:
cannot define the implicit default assignment operator for 'ModPredistCell', because non-static const member 'PLANT' can't use default assignment operator


Can someone tell me what I'm doing wrong here? Thanks.
Your constuctors are fine. The problem is exactly what the compiler is telling you: it can't automatically create an assignment operator for your ModPredistCell class because you have a const member.

This means you will have to manually overload the assignment operator for that class.
So, I need an assignment operator overload for the ModPredistCell class? Something like:

ModPredistCell& ModPredistCell::operator= (int i = 0, int32_t rv = 0)
{
PLANT = (1024 / intexp(2, i));
return *this;
}

This is an area I'm pretty green in, so please bear with me. Does this look at all correct?
no.

The assignment operator has nothing to do with the constructor. It's called when you assign something to this object.

For example:

1
2
3
4
5
6
ModPredistCell a;  // a's constructor called here
ModPredistCell b;  // b's constructor called here


b = a;  // assignment operator.
    // b's assignment operator called, with 'a' as the parameter 


The assignment operator looks like this:
1
2
3
4
5
6
ModPredistCell& ModPredistCell::operator = (const ModPredistCell& rhs)
{
  // copy 'rhs' data to '*this' data

  return *this;
}




Normally, the compiler can automatically create a generic assignment operator, which just assigns each member in the class. However it can't do that in this case, because the class has a const member, and you can't assign a const.

So your assignment operator will either have to ignore that const and leave it unchanged.... or you can eliminate the assignment operator altogether to flat out prevent object assignment.

This can be done one of two ways:

1) Make the assignment operator private and do not give it a body.

2) (C++11 only, not supported everywhere), mark the assignment operator as 'delete':
1
2
3
4
5
class ModPredistCell
{
  //...
  ModPredistCell& operator = (const ModPredistCell&) = delete;  // <- delete
};
OK, so something like this?

 
int32_t& operator= (const int32_t &i) { PLANT = i; } 


I'm not sure what you meant by "not give it a body."

EDIT:

OK, I can see how this isn't a good solution -- if I hard-code "PLANT" into the operator, it'll screw up this overload for everything else, won't it? So how do I give an assignment operator a left-hand parameter (if that's what I need to do)?

I'd greatly prefer not to use C11, for now at least.
Last edited on
OK, so something like this?


No. Something like what I posted in my previous post.


Here, let's make this simple. Put this in your class:

1
2
3
4
5
6
7
class ModPredistCell
{
  //...

private:
  ModPredistCell& operator = (const ModPredistCell&);
};


That's it. You do not have to give that assignment operator a body (as in, it can remain undefined... only having the above prototype).

This will resolve the above error you mentioned, but will forbid assigning objects of this type (you'll get a linker error if you try to assign objects from within this class, or a compiler error if you do it anywhere else).



I can try to elaborate more on the purpose and meaning of the assignment operator if you want. It doesn't seem like you really understand it. Let me know if you're interested.
Last edited on
Thank you, Disch. And yes, I'd be grateful for any enlightenment you could give me. I've never been completely comfortable with overloads; they're a bit of black magic to me.
Operator overloads work just like functions... just with more intuitive syntax.

For example, if you have a member function:
1
2
3
4
5
class MyClass
{
public:
  MyClass& Assign(const MyClass& rhs);
};


You call the member function like this:
1
2
3
MyClass a, b;

a.Assign(b);



Overloading the assignment operator is the same thing... only instead of calling a "function", it calls the overload (which basically is a function):

1
2
3
4
5
6
class MyClass
{
public:
  // instead of an "Assign" function, just use the assignment operator
  MyClass& operator = (const MyClass& rhs);
};


Then, you can "call" that operator by using the normal assignment operator:
1
2
3
MyClass a, b;

a = b;  // calls the assignment operator 


It's really that simple!




Most of the time, the assignment operator will just assign all of it's members over.
Here's an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass
{
private:
  int foo;
  int bar;

public:
  MyClass& operator = (const MyClass& rhs)
  {
    foo = rhs.foo;
    bar = rhs.bar;
    return *this;
  }
};


Pretty basic... it just assigns each member like you'd expect. This is what a properly functioning assignment operator would look like 99% of the time.

Now because it's so common, it would be really annoying if you had to do that for each class you wrote. So the compiler will automatically generate a "generic" assignment operator that does exactly what's illustrated above: it just goes through each member and assigns them.

Normally this works great. But sometimes it doesn't work so well... usually when you have pointers, or like in your case when you have a const member.

This is what was happening with you:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyClass
{
private:
  const int foo;
  int bar;

public:
  // The compiler was auto-generating this "generic" assignment operator
  //   behind the scenes
  MyClass& operator = (const MyClass& rhs)
  {
    foo = rhs.foo;  // error, cannot assign foo because it's const!
    bar = rhs.bar;
    return *this;
  }
};


This is why you were getting an error. The auto generated function was doing something illegal. So you had to get rid of it.

The auto-generated function is only generated if you do not specify your own assignment operator. So by declaring a "blank" one... that stops the compiler from auto-gen'ing the generic one, which avoids the const error. And by making it private (and not giving it a body), we ensure that it can never be called accidentally.
Thanks for the breakdown, Disch. I'll bookmark this.

Can you tell me why the "&" are needed in this operator? Why can't I just use:

ModPredistCell operator = (const ModPredistCell);
& makes it a reference.

Without passing (and returning) by reference, you are creating a copy of the object.
So, is it merely a matter of efficiency, then? Would the computation results be identical?
For the assignment operator: Yes.
Last edited on
Hey, Disch -

I need to reopen this a minute. The overload you gave me allows the code for the ModPreDistCell class to compile, but the ModPreDist class is giving me errors. The compiler didn't give me a line in my source code, but I determined that the errors are coming from my constructors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ModPredist::ModPredist(int32_t rv)
{
//    for (int i = 1; i <= NBR_CELLS; ++i)
//        cells.push_back(ModPredistCell(i, rv));
    regDelayI.assign(NBR_DELAY_REGS, rv);
    regDelayI.assign(NBR_DELAY_REGS, rv);
    regs.assign(NBR_CMPT_REGS, rv);
}

ModPredist::ModPredist(const ModPredist &mpd)
{
//    cells = mpd.cells;
    regDelayI = mpd.regDelayI;
    regDelayQ = mpd.regDelayQ;
    regs = mpd.regs;
}


The commented-out lines are generating the following error:

error: 'operator=' is a private member of 'ModPredistCell'


So, I think I see what's happening, but I'm not sure how to fix it. Do I have to declare the ModPreDist ctors as friends of the ModPredistCell class (if that's even permissible)?

Thanks.
Do I have to declare the ModPreDist ctors as friends of the ModPredistCell class (if that's even permissible)?


No. The whole point of what we did before was to disable the = operator so it can't be accessed at all.

If that's not the behavior you want, then you'll have to make it public, and give it a body. But remember that you can't change the constant value, so it might not work.


But this is strange... I don't think any of the standard container classes rely on there being an assignment operator (copy constructor, yes... but not assignment). What exactly is cells? Like what type?
definition for ModPredist:

1
2
3
4
5
6
7
8
9
10
class ModPredist {
private:
    vector<FlipFlopReg32>       regDelayI;
    vector<FlipFlopReg32>       regDelayQ;
    vector<FlipFlopReg32>       regs;
    vector<ModPredistCell>		cells;
public:
.
.
.
weird! I guess vector requires there be a valid assignment operator defined. I didn't think that was the case. In fact I find that extremely surprising.

So yeah. Looks like you'll have to define the assignment operator.


Or take the easy way out and just remove the const qualifier from that member variable (and get rid of all the assignment operator stuff).
Yeah, I think the latter is probably the better approach now.

Good education anyway. Thanks for all the help.
Using emplace_back() is also an option if your compiler supports it.
Topic archived. No new replies allowed.