很多时候,我们会看到一些在创建对象时有的加括号有的不加括号
那么,这是什么情况呢?
总结:函数需要加上括号,加上括号会对函数初始化,不加括号可能导致未知错误
我们来验证一下。
1.基本数据类型不带括号()
#include <iostream>
using namespace std;
int main(int arg, char **argv)
{
int a;
cout << "a=" << a << endl;
return 0;
}
调试结果:
2.基本数据类型带括号()
#include <iostream>
using namespace std;
int main(int arg, char **argv)
{
int a(); // 这是一个返回值为 int 无参数的函数;
return 0;
}
调试结果: 看注释
3.基本数据类型new创建不带括号()
#include <iostream>
using namespace std;
int main(int arg, char **argv)
{
int *a = new int;
cout << "a=" << *a << endl;
return 0;
}
调试结果:这是个随机值
4.基本数据类型new创建带括号()
#include <iostream>
using namespace std;
int main(int arg, char **argv)
{
int *a = new int();
cout << "a=" << *a << endl;
return 0;
}
调试结果:被初始化为 0
5.自定义数据类型不带括号(),不提任何供构造函数
#include <iostream>
using namespace std;
class A {
public:
int value;
};
int main(int arg, char **argv)
{
A a;
cout << "value=" << a.value << endl;
return 0;
}
调试结果:
6.自定义数据类型带括号(),不提任何供构造函数
#include <iostream>
using namespace std;
class A {
public:
int value;
};
int main(int arg, char **argv)
{
A a(); // 这是一个返回值类型为A的无参数函数
return 0;
}
调试结果: 看注释
7.自定义数据类型new创建不带括号(),不提任何供构造函数
#include <iostream>
using namespace std;
class A {
public:
int value;
};
int main(int arg, char **argv)
{
A *a = new A;
cout << "value=" << a->value << endl;
return 0;
}
调试结果:
8.自定义数据类型new创建带括号(),不提任何供构造函数
#include <iostream>
using namespace std;
class A {
public:
int value;
};
int main(int arg, char **argv)
{
A *a = new A();
cout << "value=" << a->value << endl;
return 0;
}
调试结果:
9.自定义数据类型不带括号(),提供构造函数
#include <iostream>
using namespace std;
class A {
public:
A() {};
public:
int value;
};
int main(int arg, char **argv)
{
A a;
cout << "value=" << a.value << endl;
return 0;
}
调试结果:
10.自定义数据类型带括号(),提供构造函数
#include <iostream>
using namespace std;
class A {
public:
A() {};
public:
int value;
};
int main(int arg, char **argv)
{
A a();// 这是一个返回值类型为A的无参数函数
//cout << "value=" << a.value << endl;
return 0;
}
调试结果: 看注释
11.自定义数据类型new创建不带括号(),提供构造函数
#include <iostream>
using namespace std;
class A {
public:
A() {};
public:
int value;
};
int main(int arg, char **argv)
{
A *a = new A;
cout << "value=" << a->value << endl;
return 0;
}
调试结果:
12.自定义数据类型new创建带括号(),提供构造函数
#include <iostream>
using namespace std;
class A {
public:
A() {};
public:
int value;
};
int main(int arg, char **argv)
{
A *a = new A();
cout << "value=" << a->value << endl;
return 0;
}
调试结果:
13.自定义数据类型new创建带括号(),提供构造函数,并是全局对象
#include <iostream>
using namespace std;
class A {
public:
A() {};
public:
int value;
};
A *a = new A();
int main(int arg, char **argv)
{
cout << "value=" << a->value << endl;
return 0;
}
调试结果:
总结: 在编写类时,只有在不给该类显式提供构造函数并在 new 对象加上括号()时, 其类内部数据成员才会被定义,其余情况都是未定义行为!
尽量为该类编写构造函数并进行一系列的初始化和赋值操作,不要依赖系统默认未定义行为。
尽量为该类编写构造函数并进行一系列的初始化和赋值操作,不要依赖系统默认未定义行为。
尽量为该类编写构造函数并进行一系列的初始化和赋值操作,不要依赖系统默认未定义行为。
首先讨论各种构造函数
我们都知道,当我们不提供构造函数时,编译器会自动为我们添加一个默认无参构造函数和一个默认拷贝构造函数,例如:
class test {};
int main() {
test A;//调用默认无参构造
test B(A);//调用默认拷贝构造
return 0;
}
当我们添加无参构造函数或者有参构造函数时,编译器将不再提供默认无参构造函数和但依旧会提供默认拷贝构造函数,例如:
//添加无参构造函数时
class test {
public:
test() { cout << "无参构造" << endl;}
};
int main() {
test A;//输出:无参构造
test B(A);//无输出,调用默认拷贝构造
return 0;
}
//添加有参构造函数时
class test {
public:
int val;
test(int _val) {
val = _val;
cout << "有参构造" << endl;
}
};
int main() {
//test A; 无法通过编译,此时没有无参构造
test A(5);//输出:有参构造
test B(A);//无输出,调用默认拷贝构造
return 0;
}
而当我们添加拷贝构造函数时,编译器将不再提供任何默认构造函数,例如:
class test {
public:
int val;
test(int _val) {
this->val = _val;
cout << "有参构造" << endl;
} //必须得添加无参构造或者有参构造,不然没法创建新对象
test(test& T) {
this->val = T.val;
cout << "拷贝构造" << endl;
}
};
int main() {
//test A; 无法通过编译,此时没有无参构造。
test A(5);//输出:“有参构造”
test B(A);//输出:“拷贝构造”
return 0;
}
新建对象时,如果使用无参构造,不添加括号。如果添加括号,编译器会认为这是函数申明,例如:
Test A;
Test A();//错误,此时编译器会认为这是函数申明,而不是无参构造
然后是new创建对象时是否添加括号
new创新新对象时,如果是内置类型,例如:int,是否添加括号都可以,添加括号会进行初始化,不添加则只是开辟空间。例如:
int* T = new int;//创建新对象,只是开辟空间
int* T = new int();//创建新对象并初始化
而对于new创建自定义对象时是否加括号,区别可以参见new对象加括号和不加括号的区别。总结就是,new创建新对象时最好加上括号。
当函数指针被赋值给另一个变量时函数调用不需要加括号
当函数指针被赋值给另一个变量时,函数调用不需要加括号是因为函数名本身就代表了函数的地址。通过将函数指针赋值给另一个变量,实际上是将函数的地址赋值给了这个变量。因此,可以直接通过这个变量来调用函数,而不需要使用括号。
这种方式可以用于实现回调函数或者动态选择要调用的函数的场景。通过将不同的函数指针赋值给同一个变量,可以在运行时决定要调用的具体函数,从而实现灵活的程序逻辑。