In the following code (which is a minimal example based on a much more complex code), a base class defines a struct local to the class. A derived class overrides this definition, but uses also the definition in the base class.
#include <iostream>
struct base {
struct update;
void apply(int& x);
};
struct base::update {
void operator()(int& x)
{
++x;
}
};
void base::apply(int& x) { update{}(x); }
struct deriv : public base {
struct update;
void apply(int& x, int& y);
};
struct deriv::update {
void operator()(int& x, int& y)
{
typename base::update{}.operator()(x);
++y;
}
};
void deriv::apply(int& x, int& y) { update{}(x, y); }
int main()
{
base b;
int x = 1;
b.apply(x);
std::cout << x << std::endl;
int y = 2;
deriv d;
d.apply(x, y);
std::cout << x << ' ' << y << std::endl;
return 0;
}
Compiling with gcc and -Wall -Wextra does not issue any warning.
The output of the code is as expected
2
3 3
However, when analyzing the code with cppcheck, with --enable=all, I get the following:
Checking test.cpp ...
test.cpp:25:24: style: Parameter 'x' can be declared with const [constParameter]
void operator()(int& x, int& y)
^
test.cpp:9:1: error: The one definition rule is violated, different classes/structs have the same name 'update' [ctuOneDefinitionRuleViolation]
struct base::update {
^
test.cpp:24:1: note: The one definition rule is violated, different classes/structs have the same name 'update'
struct deriv::update {
^
test.cpp:9:1: note: The one definition rule is violated, different classes/structs have the same name 'update'
struct base::update {
The first reported error (Parameter 'x' can be declared with const) seems clearly a false positive, as clearly I need non-const reference to be able to modify it, and in fact the code obviously does not compile with a const int&.
But what about the second error on ODR violation? Is this a correct diagnose, and if so why cannot I override the definition of update?
It is also a false positive. There is nothing wrong with declaring a nested class of the same name in the derived class. The two nested classes will be separate entities and each can have one definition per one-definition-rule.
Related
I want to create a simple program that demonstrates the usage of this. I wrote a function that prints the x and y membervariables. I defined the function on top of the file. I acutally don't even know why that is needed but ok. So far so good. Visual Studio finds zero issues, no warnings and no erros. However when I compile this code I get the following error message:
1>D:\Dev\Visual Studio Projekte\Projektmappe\FirstProject\src\This.cpp(3,30): error C2143: syntax error: missing ',' before '*'
1>D:\Dev\Visual Studio Projekte\Projektmappe\FirstProject\src\This.cpp(11,1): error C2664: 'void PrintObject(const int)': cannot convert argument 1 from 'Object *' to 'const int'
Now at some point I also got the error that no default constructor is defined. However the compiler does provide one right? I then simply retyped the code and the error disappeared. Just something I wanted to mention that also seemed stupid.
So why is the compiler thinking that "this" is referring to a "const int" when it is in fact referring to my object?
#include <iostream>
void PrintObject(const Object* o);
class Object {
public:
int x, y;
Object(int x, int y)
: x(x), y(y) {
PrintObject(this);
}
int GetX() const {
return this->x;
}
int GetXy() const {
return x;
}
};
void PrintObject(const Object* o) {
std::cout << o->x << ", " << o->y << std::endl;
}
int main() {
std::cin.get();
return 0;
}
void PrintObject(const Object* o);
You haven't declared Object yet, so the compiler cannot know what it is. You must first declare the class before delaring this function. Technically, they can both be declared at the same time, but that isn't a very popular style.
I also got the error that no default constructor is defined. However the compiler does provide one right?
It does not provide one. Default constructor is only provided for classes with no user declared constructors (and no non-default constructible sub objects).
It's simple enough, you are using Object before you are declaring it. So the compiler doesn't know what Object is at the time it reads the declaration of PrintObject.
Two possible solutions.
1) Move the declaration of PrintObject after the definition of Object.
class Object
{
...
};
void PrintObject(const Object* o);
2) Use a forward declaration to tell the compiler that Object is the name of a class.
class Object; // forward declaration
void PrintObject(const Object* o);
class Object
{
...
};
PrintObject could be defined as a member function. Would make the syntax much nicer.
#include <iostream>
class Object {
public:
Object(int x, int y)
: x(x), y(y) {
PrintObject();
}
int GetX() const {
return this->x;
}
int GetXy() const {
return x;
}
void PrintObject() const {
std::cout << x << ", " << y << std::endl;
}
private:
int x, y;
};
int main() {
Object o{5,6};
return 0;
}
Also you might want to consider, overwriting the output stream operator, if you want to define custom print for your type.
Is there a nice way to have a non static value as default argument in a function? I've seen some older responses to the same question which always end up in explicitly writing out the overload. Is this still necessary in C++17?
What I'd like to do is do something akin to
class C {
const int N; //Initialized in constructor
void foo(int x = this->N){
//do something
}
}
instead of having to write
class C {
const int N; //Initialized in constructor
void foo(){
foo(N);
}
void foo(int x){
//do something
}
}
which makes the purpose of the overload less obvious.
One relatively elegant way (in my opinion) would be to use std::optional to accept the argument, and if no argument was provided, use the default from the object:
class C {
const int N_; // Initialized in constructor
public:
C(int x) :N_(x) {}
void foo(std::optional<int> x = std::nullopt) {
std::cout << x.value_or(N_) << std::endl;
}
};
int main() {
C c(7);
c.foo();
c.foo(0);
}
You can find the full explanation of what works/doesn't work in section 11.3.6 of the standard. Subsection 9 describes member access (excerpt):
A non-static member shall not appear in a default argument unless it
appears as the id-expressionof a class member access expression
(8.5.1.5) or unless it is used to form a pointer to member
(8.5.2.1).[Example:The declaration of X::mem1()in the following example
is ill-formed because no object is supplied for the non-static
memberX::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);// error: non-static memberaused as default argument
int mem2(int i = b);// OK; useX::b
static int b;
};
I need explanation about why the following code does not compile. I have a workaround which I will articulate below, but I don't understand the failure of the original version.
To speed up code reading: The concept is to define an interface (ISomething), then to create an abstract implementation (ASomething) which implements the second function (2) using the first (not yet defined) one (1). A complete implementation which derives from the abstract one (for example SomethingImpl) must define the first method and has the option to override the second one.
#include <iostream>
class ISomething
{
public:
virtual ~ISomething()
{ }
virtual int f(int x) = 0; // (1)
virtual int f(int x, int y) = 0; // (2)
};
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
std::cout << a.f(10) << std::endl; // (1)
std::cout << a.f(10,20) << std::endl; // (2)
return 0;
}
Compiling this code gives error on both Visual Studio 2013 (Windows) and g++ 4.4.5 (Linux). The errors are very similar, I will detail the g++ output only:
$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In member function ‘virtual int ASomething::f(int, int)’:
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp:18: error: no matching function for call to ‘ASomething::f(int&)’
SibFun.cpp:16: note: candidates are: virtual int ASomething::f(int, int)
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
I tried to use different notation at (3) like return this->f(x) + this->f(y), but I experienced no significant change in the error message.
However when I changed (3) to return ISomething::f(x) + ISomething::f(y); I only got:
$ g++ SibFun.cpp -o SibFun
SibFun.cpp: In function ‘int main()’:
SibFun.cpp:36: error: no matching function for call to ‘SomethingImpl::f(int, int)’
SibFun.cpp:26: note: candidates are: virtual int SomethingImpl::f(int)
make: *** [SibFun] Error 1
But! When change (2) from f to g all compiles and runs as expected.
What is the reason behind this begavior? Why can't I use the f name for (2)?
Function overloading works only for functions visible in the same scope:
class ASomething
: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
using ISomething::f;
//~~~~~~~~~~~~~~~~~^
};
class SomethingImpl
: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
using ASomething::f;
//~~~~~~~~~~~~~~~~~^
};
Both compilation failures happen for the same reason. While you're overriding one virtual member function, you're hiding the other. In ASomething:
virtual int f(int x, int y) // (2)
{
return f(x) + f(y); // (3)
}
Name lookup on f finds ASomething::f and stops, it doesn't keep going to look for other overloads. Since ASomething::f takes two arguments, and you're trying to call it with one, error. In order to allow for overloading against the base class, you have to introduce the base class member functions with a using-declaration:
using ISomething::f; // NOW, ISomething::f(int ) is found by lookup
virtual int f(int x, int y)
{
return f(x) + f(y);
}
And similarly, SomethingImpl needs a using ASomething::f; statement so that a.f(10) can compile.
The problem is not an 'overloading' problem, but hiding a base class function (See other answers)
A slightly modified example:
#include <iostream>
class ISomething
{
public:
virtual ~ISomething() {}
virtual int f(int x) = 0; // (1)
virtual int f(int x, int y) = 0; // (2)
};
class ASomething: public virtual ISomething
{
public:
virtual int f(int x, int y) // (2)
{
// `this->f(x)` fails:
ISomething& i = *this;
return i.f(x) + i.f(y); // (3)
}
};
class SomethingImpl: public ASomething
{
public:
virtual int f(int x) // (1)
{
return x+1;
}
};
int main()
{
SomethingImpl a;
// `a.f(10, 20)` fails:
ISomething& i = a;
std::cout << i.f(10) << std::endl; // (1)
std::cout << i.f(10, 20) << std::endl; // (2)
return 0;
}
Hence, calling f from the interface, resolves the conflict. Although, you should consider using base::f, as suggested in other answers.
That is not a duplicate. Please read carefully. There are two variables x (of type int and X) and one member is actually declared private, which is used in a constructor. It is about understanding the constructor process in this very specific case.
I am doing a C++ course and I understand the following example that was given. It is about constructors.
#include <iostream>
using namespace std;
class Element {
int value;
public:
Element(int val) {
value = val;
cout << "Element(" << val << ") constructed!" << endl;
}
int Get(void) {
return value;
}
void Put(int val) {
value = val;
}
};
class Collection {
Element el1, el2;
public:
Collection(void) : el2(2), el1(1) {
cout << "Collection constructed!" << endl;
}
int Get(int elno) {
return elno == 1 ? el1.Get() : el2.Get();
}
int Put(int elno, int val) {
if (elno == 1) el1.Put(val);
else el2.Put(val);
}
};
int main(void) {
Collection coll;
return 0;
}
Then they mentioned the following
...
We should also add that there is the following alternation for that
case: when the constructor is divided between the declaration and the
definition, the list of alternative constructors should be associated
with the definition, not the declaration.
It means that the following snippet is correct:
class X {
public:
X(int x) { };
};
class Y {
X x;
public:
Y(int x);
};
Y::Y(int x) : x(1) { };
Can someone explain? Is it really correct? And if yes, how to interpret that? Y has a one-parameter constructor, but no value is passed. x(1) is probably the constructor for the field X x in Y. Is the value of 1 (of x(1)) then passed to Y(int x) automatically although it is declared private in Y?
In the second code snippet, there is no construction actually going on—it's just a definition of the classes and constructors. The only "special" thing about it is that the body of Y's constructor is defined outside the class; it could be in a different file, for example. In this case, it's no different from putting the body directly into the class1:
class Y {
X x;
public:
Y(int x) : x(1) {}
};
When this constructor of Y is invoked, it constructs the member variable x by passing 1 to the X constructor taking int. The constructor of Y doesn't do anything else, i.e. it ignores its own parameter.
The syntax Y::Y used in the original code snippet is standard syntax for defining a member function outside of the class definition. For a non-constructor, it would look like this:
class Foo
{
int bar() const;
};
int Foo::bar() const
{
return 42;
}
1 With the slight difference that when put directly into the class definition, the function is implicitly inline (can be present in more than one translation unit).
I've been messing about with member-function pointers in relation to a previous question. In the code below I call methods on a class (B) that change a variable (count) in it, but I never make an instance of this class. Why does this work?
#include <iostream>
#include <string>
#include <map>
class A;
typedef int (A::*MEMFUNC)(int, int);
#define HANDLER(aclass, aproc) (MEMFUNC)(&aclass::aproc)
enum
{
ADD=1,
MUL,
SUB,
DIV
};
class B
{
int count;
public:
B() : count(0) {}
~B() {}
int multiply(int x, int y) { count++; return x*y*count; }
int divide(int x, int y) { count++; if (y!=0) return (x/y)*count; else return 0; }
};
class A
{
std::map< int, MEMFUNC > funcs;
public:
A() { AddLocals(); }
~A() {}
int CallLocal(int nID, int x, int y)
{
MEMFUNC f = funcs[nID];
if (f) return (this->*f)(x, y);
else return 0;
}
void AddLocals()
{
Add(ADD, HANDLER(A, plus));
Add(MUL, HANDLER(B, multiply));
Add(SUB, HANDLER(A, subtract));
Add(DIV, HANDLER(B, divide));
}
void Add(int nID, MEMFUNC f) { funcs[nID] = f; }
int plus(int x, int y) { return x+y; }
int subtract(int x, int y) { return x-y; }
};
int main()
{
A aA;
int a,b,c,d;
a = aA.CallLocal(ADD,8,2);
b = aA.CallLocal(MUL,8,2);
c = aA.CallLocal(SUB,8,2);
d = aA.CallLocal(DIV,8,2);
std::cout << "a = " << a << "\n"
<< "b = " << b << "\n"
<< "c = " << c << "\n"
<< "d = " << d << "\n";
return 0;
}
(sorry, me again, but this member-function pointers are making me itch)
Your cast in the HANDLER macro def tells the compiler "Shut up! I know what I'm doing!".
So the compiler shuts up.
You still have Undefined Behavior, but one property of UB is that in some cases it does what you'd naïvely expect, or what you'd want it to do.
But don't be surprised if such code crashes, or causes crashes or mysterious incorrect result in apparently totally unrelated code.
Or, for example, causes nasal demons to fly out your nose.
Cheers & hth.
The result is just undefined behavior. For example, I get that b = 2083899728 and d = -552766888.
The persistent thing you are manipulating is most likely an int's worth of bytes in the map instance of A (because if the object were indeed a B, then that's the offset where the count member would be located.
In my stdlib implementation, the first member of map is the comparison function, in this case an instance of std::less<int>. Its size is 1, but there must be unused padding bytes after that to align the other members of map. That is, (at least) the first four bytes of this instantiation of std::map contains just garbage that is not used for anything (std::less doesn't have data members and doesn't store state, it just takes space in the map). That would explain why the code doesn't crash - it is modifying a part of the map instance which doesn't affect the functioning of the map.
Add more data members in B before count, and now count++ will affect crucial parts of the map's internal representation and you can get a crash.
C-casting lets you get away with all sorts of horrid behaviour but doesn't mean it's ok to do it so simply don't.
Get rid of your macro completely and do not cast. You can probably use boost::function and boost::bind to get the behaviour you actually want.
Your code is invoking undefined behaviour by trying to call a member of class B using an object of class A.
We can try to explain how the compiler can come to the behaviour you have observed, but there is no guarantee that you will get the same behaviour if you change anything (add/remove a member, change compiler settings or use a different compiler).
With the cast in the HANDLER macro, you are telling the compiler not to warn you about the use of incompatible types but just to do as you tell it to. In this case, you tell the compiler to reinterpret the address of a member of any class as being the address of a member of class A.
When you later try to call, for example, B::multiply, that function does not know that it is not working on an object of class B, so it will happily clobber the bytes of aA that would correspond to the B::count member if it had been a B object. Most likely, these bytes are actually being used by A::funcs, but apparently not for anything critical. If you change class A to:
class A
{
int count;
std::map< int, MEMFUNC > funcs;
public:
A() : count(0) { AddLocals(); }
~A() {}
int CallLocal(int nID, int x, int y)
{
MEMFUNC f = funcs[nID];
if (f) return (this->*f)(x, y);
else return 0;
}
int Count()
{
return count;
}
void AddLocals()
{
Add(ADD, HANDLER(A, plus));
Add(MUL, HANDLER(B, multiply));
Add(SUB, HANDLER(A, subtract));
Add(DIV, HANDLER(B, divide));
}
void Add(int nID, MEMFUNC f) { funcs[nID] = f; }
int plus(int x, int y) { return x+y; }
int subtract(int x, int y) { return x-y; }
};
then printing the result of aA.Count() at various places might show the effect.
The compiler is calling the expected function, because they are non-virtual member functions.
The only difference between non-member functions and non-virtual member functions is in the hidden argument that feeds the this pointer in a member function. So, if you take the address of a non-virtual member function, you will get a fixed address that is distinct for every function.
If the member functions had been virtual, then the compiler would, most likely, have returned the index into the v-table as a pointer for that function (together with some kind of indication that it is a v-table offset). Then the code can determine at the call-site if it can do a direct call to the member function or if it needs to do an indirect call through the v-table of the object the function is called on.