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.
Related
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.
I have a class MyClass. In it, I want to create an array of function pointer and initialize the array with the functions of another class (MemberClass).
MyClass has a pointer to MemberClass as member.
but I get this compile time error
error C2440: 'initializing' : cannot convert from 'void (__thiscall MyMemberClass::* )(void)' to 'F'
//This class has the function that I want to create a function pointer to
class MemberClass
{
private:
int myValue1;
int myValue2;
public:
int GetValue1() //I want to point to this function from a function pointer in another class
{
return myvalue1;
}
int GetValue2() //I want to point to this function from a function pointer in another class
{
return myvalue2;
}
}
//This has array of function pointer that I want to point to member function of another class
Class MyClass
{
typedef void(*F)();
private:
MemberClass* mclass;
F[] f;
Process();
}
.cpp
MyClass::MyClass()
{
f[2] = {&MemberClass::GetValue1, &MemberClass::GetValue2} //This line throws error
//error C2440: 'initializing' : cannot convert from 'void (__thiscall MyMemberClass::* )(void)' to 'F'
}
void MyClass::Processing()
{
//This is how I am hoping to use the function pointer array
F[Index]();
}
F is declared as pointer to function with no parameters returning void. But your functions return int, and are member functions of MemberClass rather than plain ordinary functions. So the type you need is
typedef int (MemberClass::*F)();
Calling it is also more interesting:
int result = (mclass->*f[index])();
Suggestion: rather than a method pointer, use C++11's functional library.
I'm butchering OP's sample code slightly to simplify the example.
MemberClass stays mostly the same. I removed the member variables because the methods are now hard-coded to return 1 and 2 to make them easy to tell apart.
#include <iostream>
#include <functional>
class MemberClass
{
public:
int GetValue1()
{
return 1;
}
int GetValue2()
{
return 2;
}
};
myClass gets a rip-up because this is where the action is.
class MyClass
{
private:
I'm using an array of std::function instead of a typedef and an array of the typedef. Note the template argument int(). This is an array of functions that takes nothing and returns an int. Magic in std::bind will provide the hidden this parameter required by methods. If the function has parameters that are not known at the time of binding, use std::placeholders to save room to them in the method's parameter list.
Since the methods are bound to their object, there is no longer any need to store MemberClass* mclass;
std::function<int()> f[2];
public:
Calling the function is simple: index the array and stick the brackets on.
int Process(int index)
{
return f[index]();
}
The constructor is either a bit trickier, or less tricky, depending on your school of thought. I'm using an initializer list because it is cleaner (to me, at anyrate) and often has performance advantages. For one thing, you can swap out the array for a std::vector or most other containers without having to change a line of code other than the variable definition.
f[0] = std::bind(&MemberClass::GetValue1, mem);
f[1] =...
inside the body of the constructor is still an option.
MyClass(MemberClass * mem):
f{std::bind(&MemberClass::GetValue1, mem),
std::bind(&MemberClass::GetValue2, mem)}
{
}
};
And a silly little bit of test code to make sure this all works. Why? Because every time you don't test code in it's simplest form you're taking an unnecessary risk. If it doesn't work small, it won't work big.
int main()
{
MemberClass c;
MyClass d(&c);
std::cout << d.Process(0) << std::endl;
std::cout << d.Process(1) << std::endl;
}
All together for one cut and paste-able block:
#include <iostream>
#include <functional>
class MemberClass
{
public:
int GetValue1()
{
return 1;
}
int GetValue2()
{
return 2;
}
};
class MyClass
{
private:
std::function<int()> f[2];
public:
int Process(int index)
{
return f[index]();
}
MyClass(MemberClass * mem):
f{std::bind(&MemberClass::GetValue1, mem),
std::bind(&MemberClass::GetValue2, mem)}
{
}
};
int main()
{
MemberClass c;
MyClass d(&c);
std::cout << d.Process(0) << std::endl;
std::cout << d.Process(1) << std::endl;
}
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 am trying to understand how default constructor (provided by the compiler if you do not write one) versus your own default constructor works.
So for example I wrote this simple class:
class A
{
private:
int x;
public:
A() { std::cout << "Default constructor called for A\n"; }
A(int x)
{
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main (int argc, char const *argv[])
{
A m;
A p(0);
A n();
return 0;
}
The output is :
Default constructor called for A
Argument constructor called for A
So for the last one there is another constructor called and my question is which one and which type does n have in this case?
A n();
declares a function, named n, that takes no arguments and returns an A.
Since it is a declaration, no code is invoked/executed (especially no constructor).
After that declaration, you might write something like
A myA = n();
This would compile. But it would not link! Because there is no definition of the function n.
A n();
could be parsed as an object definition with an empty initializer or a function declaration.
The language standard specifies that the ambiguity is always resolved in favour of the function declaration (§8.5.8).
So n is a function without arguments returning an A.
For the last one NO constructor gets called.
For that matter no code even gets generated. All you're doing is telling (declaring) the compiler that there's a function n which returns A and takes no argument.
No there is not a different constructor.
A n();
is treated as a declaration of function taking no arguments and returning A object. You can see this with this code:
class A
{
public:
int x;
public:
A(){ std::cout << "Default constructor called for A\n";}
A(int x){
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main(int argc, char const *argv[])
{
A m;
A p(0);
A n();
n.x =3;
return 0;
}
The error is:
main.cpp:129: error: request for member ‘x’ in ‘n’, which is of non-class type ‘A()’
I stumbled upon this piece of code in the openCV source ( cxoperations.hpp, line 1134, in the definition of the Vector class ):
Vector(const Vector& d, const Range& r)
{
if( r == Range::all() )
r = Range(0, d.size());
// some more stuff...
}
Note that the Vector class has no data member called r (and indeed, the identifier r only occurs in one more place in the entire class definition, as a parameter in another method). So apparently, that right there is an assignment to a const reference.
I tried to reproduce a minimal example:
#include <iostream>
class Foo
{
public:
int _a;
Foo(int a) : _a(a) {}
};
int main()
{
Foo x(0);
const Foo& y = x;
printf("%d\n", y._a);
y = Foo(3);
printf("%d\n", y._a);
}
This, of course, fails to compile: g++ gives the error
test.cpp:15: error: passing `const Foo' as `this' argument of `Foo& Foo::operator=(const Foo&)' discards qualifiers
The only way I got it to work is by overriding operator= like this:
#include <iostream>
class Foo
{
public:
int _a;
Foo(int a) : _a(a) {}
Foo& operator=(Foo rhs) const
{
Foo& tmp = const_cast<Foo&>(*this);
tmp._a = rhs._a;
return const_cast<Foo&>(*this);
}
};
int main()
{
Foo x(0);
const Foo& y = x;
printf("%d\n", y._a);
y = Foo(3);
printf("%d\n", y._a);
}
This compiles, and prints "0 3" as expected. The problem here is that
anyone who writes code like that should have their hands cut off
in the openCV source above, there is no redefinition of operator= that takes Range parameters (Range-related functions are just above the definition of Vector, starting at line 1033)
Obviously I'm missing something, since the openCV source compiles. My question is, what is really going in in the r = Range(0, d.size()); line that makes it legal?
I notice cv's Vector is a class template. So if that class method was never instantiated, there was no compiler error. My guess is that if you try
Vector<int> a;
Vector<int> b(a, Range::all());
you'll get a compiler error on that suspicious-looking line. Then you can report it as a bug in the OpenCV source.
My theory is that the offending code is never used and therefore never instantiated. Vector is a template, after all.
Consider this code:
template <class T>
class Vector
{
public:
Vector()
{
}
Vector(const Vector & x, const int & y)
{
y = 54;
}
};
// template class Vector<float>;
void foo()
{
Vector<float> v1;
// Vector<float> v2(v1, 42);
}
GCC (version 4.5.1) accepts this, but complains as soon as you add that call to the second constructor or the eplicit template instantiation.
I suggest you submit it as a bug report here, or post your message to the OpenCV newsgroup either at Y!G or to directly to the dev-list at "opencvlibrary-devel#lists.sourceforge.net".