assuming we have the next function object:
class foo{
private:
int counter;
public:
foo(int counter): counter(counter){}
foo& operator=(const foo& ){...}
bool operator() (int variable){....}
}
int main(){
foo f(4);
foo x(5);
x = f(4);
return 0;
}
how does the compiler knows how to respond to:
x = f(5)?
I've been searching for a while on the web and in Stack and haven't found exact answer, if its a repost , tell me and i'll delete the question.
It depends on whether the "(5)" is being used to construct an object or called on an already-existing object:
foo f(5); // calls the constructor
f(5); // calls operator()
I added a simple method called eval to explain it:
class foo {
private:
int counter;
public:
foo(int counter): counter(counter) {}
bool operator() (int variable) {
return variable < counter;
}
bool eval(int variable) {
return variable < counter;
}
};
foo is a class not a method.
an instance of foo can be used like a method.
calling foo(5) will create an instance of foo where the counter = 5.
eval is a member function of foo. (for now this will do the same as the () operator)
You can call eval like this:
foo f = foo(5); // create an instance of `foo`
f.eval(3); // returns true -> 3 < 5
f.eval(0); // returns false -> 6 < 5
You can also use the () operator:
foo f = foo(5); // create an instance of `foo`
f(3); // returns true -> 3 < 5
f(0); // returns false -> 6 < 5
NOTE:
You can also write (but don't do it):
foo f = foo(5); // create an instance of `foo`
f.operator()(3); // returns true -> 3 < 5
f.operator()(0); // returns false -> 6 < 5
Related
Having the following class with the operator()(string) function and the constructor X(string):
class X
{
public:
string n;
X(string s) : n(s) {}
void operator() (string s)
{
cout << "func";
}
};
Why doesn't X x("a"),y("b"); raise any errors? How does the compiler knows which function to choose?
X x("a"),y("b");
Is equivalent with
X x("a");
X y("b");
So I will focus on
X x("a");
This is a declaration and initialization of the variable x. Only constructors and conversions (*) are considered.
operator() is the function call operator. It is used to call on a object as if it were a function. So it is used on an existing object. E.g.:
X x("asd"); // <-- constructor call
x("yolo"); // <-- operator() call
As a side note I recommend using the brace init syntax {} to initialize objects:
X x{"asd"};
auto x = X{"asd"};
*) As a bonus, here is an example of an user defined conversion operator used:
struct X { };
struct Y
{
operator X() const { return X{}; }
};
auto test()
{
Y y;
X x(y);
// the above line is equivalent with:
X x = static_cast<X>(y.operator X());
}
I used X x(y) to mimic your example, but again, I recommend:
auto test()
{
Y y{};
X x{y};
}
instead
I want to explicitly change the second parameter in a constructor of a struct, in the following scenario. Is it possible, if so, how?
struct foo{
int x;
int y;
foo(int a=4, int b=6){
x=a;
y=b;
}
};
int main(){
foo *f = new foo();
cout<<f->x<<" "<<f->y<<endl;
//4 6
foo *g = new foo(3,4);
cout<<g->x<<" "<<g->y<<endl;
//3 4
foo *h = new foo(3);
cout<<h->x<<" "<<h->y<<endl;
//3 6
//Can something like this be
//done in C++, if I want
//to change the value of the
//second variable only
foo *k = new foo(b = 13);
return 0;
}
Is it possible, if so, how?
It is not possible with constructor. In general, c++ does not support named keyword arguments to functions, and it is not possible to skip arguments even if they have a default, if you want to pass a non-default after it.
It will be possible without constructor using list initialisation syntax since C++20 using designated initialisers, if you use default member initialisers:
struct foo{
int x = 4;
int y = 6;
};
int main(){
foo f {.y = 4};
}
You can achieve something similar with tag dispatching; No need for future standard:
struct foo{
int x = 4;
int y = 6;
enum Xtag { Xinit };
enum Ytag { Yinit };
foo(int a, int b) : x(a), y(b) {}
foo(Xtag, int a) : x(a) {}
foo(Ytag, int b) : y(b) {}
};
int main(){
foo f(foo::Yinit, 4);
}
A solution using lambda that can be used without modifying an existing class. Following works with your definition of foo:
auto make_foo_x4 = [](int b) {
return foo(4, b);
};
foo f = make_foo_y(4);
The downside is that we have to explicitly repeat the default value of x, so this can break assumptions if the default is changed in class definition.
For example, there is a class foo :
class foo {
public:
foo (int = 10);
.....
}
The prototype of the constructor has "int = 10" inside. So, what does it mean? Int is just an integer type, isn't? So, isn't that illegal to assign a value to it? I was trying to find such an example in Prata's book, and everywhere else, but I didn't find the explanation.
You can omit the name of parameter in function declaration (in definition too), but still you are able to specify default value of that parameter.
Consider:
void f(int x = 10) {
printf("%d\n", x);
}
void g(int = 10);
void g(int x) {
printf("%d\n", x);
}
int main() {
f();
g();
return 0;
}
Result:
10
10
The same situation is in the constructor case.
So, isn't that illegal to assign a value to it?
There is absolutely no assignment involved here. The = character can have quite different meanings in C++:
Assignment: i = 0;
Initialisation: int i = 0;
Making a member function pure virtual: virtual void f() = 0;
Specifiying default arguments: void f(int i = 0);
The latter is what you have encountered. A constructor can have default arguments like any other normal function.
I try to implement copy on write using a pointer on integer. But I don't understand how to write the code. The idea is very clear in my head: when I use the default constructor, I create a new instance of the object (number of instances=1) and when I use the copy constructor, I increment the number of instances and make a shallow copy of the object.
class Myclass
{
public:
Myclass(const char * foo, int foo2) : foo(foo), foo2(foo2)
{
(*ref)=1;
}
Myclass(const Myclass& rhs) :foo(rhs.foo),foo2(rhs.foo2)
{
(*ref)++;
}
const char * foo;
int foo2;
int *ref;
};
I begin with C++ and the notion of pointer is completely news for me so I tried this.
But I really don't understand why "ref" is still equal to 1 even if I create a copy of the object witht he copy constructor.
Your default constructor needs to create a new reference count:
ref(new int(1))
And your copy constructor needs to make the new object end up with a pointer to the original object's reference count and to increment it (which you already do):
ref(rhs.ref)
I'm having trouble understanding what you want but I'll try...
I create Myclass foo ("foo",10) and then Myclass foo2(foo). I want
all ref to be equal to 2. Here only the ref of foo2 is equal to 2.
The ref of foo is equal to 1. I think I need a pointer, no?
This can be accomplished with a static variable:
class Myclass
{
public:
Myclass(const char * foo, int foo2) : foo(foo), foo2(foo2)
{
ref += 1;
if (1 == ref) {} // First ref, do something?
}
Myclass(const Myclass& rhs) :foo(rhs.foo),foo2(rhs.foo2)
{
ref += 1;
}
~Myclass() // Decrement on delete
{
ref -= 1;
if (0 == ref) {} // Last reference. Do something?
}
const char * foo;
int foo2;
static int ref;
};
int Myclass::ref = 0; // Initialize to 0
Then....
Myclass foo("foo",10); // ref becomes 1
Myclass foo2(foo); // ref becomes 2
Myclass *foo3 = new Myclass(foo); // ref becomes 3
delete foo3; // ref becomes 2
I wrote the following code:
#include <iostream>
using namespace std ;
class C{
public:
C::C(int) ;
int f1(int);
int f2(int);
int (*f)(int);
}
int C::f1(int x){
return -x ;
}
int C::f2(int x){
return x;
}
C::C(int c){
if (c<0){
f = f1 ;
}
else {
f = f2 ;
}
}
This code doesn't work, but the idea is that I want the method f to be assigned either to f1 or to f2 depending on the value passed to the constructor.
How can I achieve this in C++?
If your member functions are non-static, then you have to declare f as a member function pointer:
int (C::*f)(int);
Given the name m of a member function of class C, you get member function pointers to m by writing:
&C::m
In your case:
if (c<0){
f = &C::f1;
}
else {
f = &C::f2;
}
Here is a live example with the full code.
Invoking your member function through the pointer-to-member f will then require the use of operator ->* or .*. For instance:
int main()
{
C c(42);
(c.*(c.f))(1729);
int (C::*fxn)(int) = c.f;
(c.*fxn)(0);
C* p = &c;
(p->*fxn)(123);
}
Or, from inside a given member function fxn of C:
void C::fxn()
{
// ...
(this->*f)(6);
}
On the other hand, if your functions f1() and f() do not need to work on a specific instance of C, you could leave the declaration of f as is as well as the code in C's constructor, but you would have to mark f1() and f2() as static:
class C
{
public:
C(int);
static int f1(int);
// ^^^^^^
static int f2(int);
// ^^^^^^
int (*f)(int);
};
You can normally do this but you need to mark f1 and f2 as static. Otherwise they need a this pointer which normally can't be stored in the function pointer.
class C
{
public:
C(int);
static int f1(int);
static int f2(int);
int (*f) (int);
};
int C::f1(int x)
{
return -x;
}
int C::f2(int x)
{
return x;
}
C::C(int c)
{
if (c < 0) {
f = f1;
} else {
f = f2;
}
}