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.
Related
I have come across this overridden function-call operator() inside a IonizationTunnel.h file:
void operator()(Particles *, std::vector<double>*, unsigned int, int ipart_ref = 0) override;
This matches exactly with the parameters of a virtual void operator() inside a Ionization.h file:
virtual void operator()(Particles *, std::vector<double>*, unsigned int, int ipart_ref = 0) {}
Ionization is the Base class. IonizationTunnel is the Derived class.
2 questions:
What does a parameter with no-name inside the argument list mean? I.e. the pointer to a Particles object, Particles*. Or the unsigned int without a name. Why do they appear like that and what do they mean?
What does the parameter with a name (so an usual parameter) being set to a value inside () mean?
I.e. int ipart_ref = 0. Does it mean that when we'll call IonizationTunnelObject.operator()(arguments) we have to specify 3 arguments and not 4, the last argument (ipart_ref) being silently inferred to be 0 even if not written in the 3 arguments we specify? Or can we call IonizationTunnelObject.operator()(arguments) using 4 arguments and set ipart_ref to any integer value we want?
I am accustomed to seeing foo(int x) {code} and I have never seen foo(int) {code}.
Thank you a lot!
An unused parameter that does not necessarily need a name can be useful sometimes to let overload resolution pick the desired overload:
void foo(int) {
std::cout << "this is foo(int)\n";
std::cout << "I dont need a name for the argument, because I am not using it anyhow";
}
void foo(double) {
std::cout << "this is foo(double)";
}
foo(1); // calls foo(int)
foo(1.0); // calls foo(double)
However, what you see is probably just the names omitted on the declaration and on the definition they will be given names, as in:
void foo(int); // forward declaration
void bar(int x) {
if (x==42) foo(x); // needs a declaration of foo
}
void foo(int x) { // definition
if (x!=42) bar(x);
}
The = something is default arguments. A function
void foo(int x = 0) {
std::cout << x;
}
Can be called either like this:
foo(42);
or like this:
foo();
in which case it is equivalent to calling
foo(0);
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;
};
If I override a virtual method, can I change the name of an argument in the child? Same type of argument, just change say (int num) to (int n)?
Is this example valid?
class Animal
{
public:
virtual int foo(int num) {
return num + 1;
}
};
class Cat : public Animal
{
public:
int foo(int n) override {
return n - 1;
}
};
If it is, why do argument names not matter?
The name of the argument is irrelevant.
The only thing that must match is the type of the parameter.
And also whether the class method itself is const, or not. And the method's return value must match.
To give a proper answer, the names of the arguments do not matter because they are not part of function signature. See http://en.cppreference.com/w/cpp/language/function for (quite comprehensive) explanation.
By the way, const-ness of the argument itself is not part of the signature either. This way, void foo(const int x); and foo (int x) are equivalent.
I compiled the code with an additional:
int main() {
// your code goes here
Animal a;
Cat c;
cout << a.foo(4) << endl;
cout << c.foo(4) <<endl;
return 0;
}
This ran and gave the expected output of 5, 3.
So it seems changing argument names is perfectly valid.
You can as long as parameters are scoped to the function being declared to. What matters is the number of parameters and type so be sure that the overriden function has the same signature as the base's
class Animal
{
public:
virtual int foo(int) { // even no parameter identifier and it is ok
return 0;
}
};
class Cat : public Animal
{
public:
int foo(int n) {
return n - 1;
}
};
While using virtual method, all you need to do is to keep the declaration of the method same. That is, if I talk about your code you can change the variable number but not the datatype, parameter list, return type and function name.
I have template function change that takes a function that takes int and returns an object of type A. So I thought I can use the constructor of A
class A {
int y;
public:
explicit A(int y) : y(2 * y) {
}
};
class B {
A x;
public:
B(int x) : x(x) {
}
template<typename F>
void change(int y, F func) {
x = func(y);
}
};
int main(void) {
B b(7);
b.change(88, A()); // << here
return 0;
}
But the compiler says no matching function for call to ‘A::A()’
How can I make it works?
You can't pass a constructor as a parameter like you are attempting. The C++ standard is very strict on not allowing the memory address of a constructor to be taken.
When you call change(88, A()), you are actually constructing a temp A object (which the compiler should not allow since A does not have a default constructor) and then you are passing that object to the parameter of change(). The compiler is correct to complain, since A does not define an operator()(int) to satisfy the call to func(y) when called in an A object.
To make this work, you need to create a separate function that constructs the A object, and then pass that function to change(), eg:
A createA(int y)
{
return A(y);
}
int main(void) {
B b(7);
b.change(88, createA);
return 0;
}
I see this code and I can't understand what it mean.
I know how we use default constructor but this is not default constructor. What is this?
class X
{
...
};
int main()
{
X f();
}
It declares a function f which takes no parameters and returns a type X.
This is also known as Most Vexing Parse in C++. It is a byproduct of the way the C++ standard defines the interpretation rules for declarations.
Assume you declare a function:
int Random();
And use it:
int main()
{
int n;
n = Random();
}
But implement the Random function after main. Or assume that Random function is defined in some header. You need to instruct the compiler that Random is a function implemented in some other source file, or in some library.
Therefore, an expression like:
T foo();
Would always mean a instruction to compiler that there is a function named foo which returns T. It cannot be an object of type T.
Its function declaration of name f
X f();
^ ^ function
return type
function f() takes no arguments and returns a X class object.
for example its definition can be like:
class X{
int i;
// other definition
}
X f(){
X x;
// some more code
return x;
}
In main you can use like:
int main(){
X a = f();
int i = f().i;
}
This is a function which doesn't take any argument and returns an object of class X