- 将数组传入函数
- 函数的地址与函数的指针
- 函数的 static 与 inline
- 引用左值和引用传参
- C++11 的数组 for 循环
- 64 位 Linux 操作系统中 C++ 中常见基本类型所占字节数
- C++11 类成员变量的初始化
- 友元可以访问类的私有变量
将数组传入函数
void test(int array[]);
void test(int* array);
两种传递方式完全等价,但是第一种传递方式的可读性更高。
禁止修改数组的值
void test(const int array[]);
void test(const int* array);
注意,const 能用则用,如果声明函数时。函数的参数是带 const 的,则函数可以接受带 const 或不带 const 的参数。若函数参数不带 const,则只能接受不带 const 的参数。
函数的地址与函数的指针
#include <iostream>
using namespace std;
void myPrint()
{
cout<< "myPrint\n";
return;
}
void getResult(void (*printMethod)(void)) // 函数的参数为函数指针/地址
{
(*printMethod)(); // printMethod(); 同样有效
return;
}
int main(int argc, char** argv)
{
void (*myPrintPtr)(void); // 函数指针
myPrintPtr = myPrint; // 将函数地址赋值给函数指针
cout<< "myPrint 函数地址:"<< (void*)myPrint<< endl; // 由于cout没有输出函数地址类型的重载,因此需要显示的将函数地址声明为指针类型才能有效输出。否则会默认输出boolean值
cout<< "myPrint 函数指针:"<< (void*)myPrintPtr<< endl; // 由于cout没有输出函数指针类型的重载,因此需要显示的将函数指针声明为指针类型才能有效输出。否则会默认输出boolean值
cout<< "myPrint 函数指针地址:"<< &myPrintPtr<< endl;
getResult(myPrint); // 可以接受函数地址
getResult(myPrintPtr); // 可以接受函数指针
return 0;
}
myPrint 函数地址:0x55b39f80097a
myPrint 函数指针:0x55b39f80097a
myPrint 函数指针地址:0x7ffd48cd26b0
myPrint
myPrint
注意,下列示例中,直接将函数声明为指针是不合法的:
void (*myPrint)()
{
cout<< "myPrint\n";
return;
}
函数的指针只是一个指针,不能像函数一样链接代码块。
函数的指针数组
void (*ptr[3])(void) = {func1, func2, func3}; // 声明并初始化一个包含三个函数地址的函数指针数组
上述代码可以使用 typedef 简化:
typedef void(*void_ptr)(void);
void_ptr pa[3] = {func1, func2, func3};
函数的 static 与 inline
- static 静态函数。限制函数的作用域为本文件,不能够被其他文件调用
- inline 内联函数。建议编译器将函数体嵌入调用他的地方,类似于宏定义的替换。这样可以使得函数在被调用时,程序不需要跳转到函数处,可以提高效率,但占用内存。inline 修饰的函数不能够先声明后定义,只能够直接进行定义。
引用左值和引用传参
- 当将临时变量赋给引用时,该引用需要被const修饰
double a = 10.0; const int & b = (int)a; // (int)a 产生临时变量,一般来讲,右值表达式都将产生临时常量。临时常量无法被寻址,在左值处加入 const 修饰会让编译器创建一个无名常量记录临时常量的信息,该无名常量可以被寻址,但不可以被改变。
- 以普通引用作为形参的函数不能接收常量作为实参传递
#include <iostream> using namespace std; void test(int & a); int main() { const int a = 10; // 常量 test(a); // 将常量传递给普通引用函数 return 0; } void test(int & a) { cout<< a<< endl; }
报错:test.cpp:10:8: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
- 当函数以常量引用作为形参时,可以接受非常量传参
- 更多细节参考文章
C++11 的数组 for 循环
int a[] = {1, 2, 3, 4};
for(int b:a)
{
cout<< b<< " ";
++b;
}
cout<< endl;
for(int b:a)
{
cout<< b<< " ";
}
cout<< endl;
1 2 3 4
1 2 3 4
这里第一个for循环中的数组a中的每一个值相当于按值传递给b,b的地址是唯一的且不指向a数组中的值。修改b无法修改a数组。
int a[] = {1, 2, 3, 4};
for(int & b:a)
{
cout<< b<< " ";
++b;
}
cout<< endl;
for(int b:a)
{
cout<< b<< " ";
}
cout<< endl;
1 2 3 4
2 3 4 5
想要修改a数组,则需要在第一个for循环中,让a数组中的值传引用到b,此时b指向a数组中的值,修改b可以修改a数组。
64 位 Linux 操作系统中 C++ 中常见基本类型所占字节数
pointer: 8字节
char : 1字节
unsigned char : 1字节
char16_t : 2字节
short : 2字节
unsigned short : 2字节
char32_t : 4字节
w_char : 4字节
int : 4字节
unsigned int : 4字节
float : 4字节
long : 8字节
long long : 8字节
unsigned long (long) : 8字节
double : 8字节
long double : 16字节
字节数比指针大的,声明函数时按参传递会有优势。
C++11 类成员变量的初始化
默认成员初始化器
在声明变量时直接初始化
class Baby
{
public:
Baby(const std::string name) : _name_(name) {}
Baby(int age) : _age_(age) {}
private:
// 默认成员初始化, 在声明处就进行初始化。
std::string _name_ = "Unknown";
int _age_ = 0;
int _weight_ = 0;
int _height_ = 0;
};
成员变量初始化列表
class Baby
{
public:
// 采取成员初始化列表方式,大量成员变量在多个初始化列表中重复出现
Baby(const std::string name):_name_(name), _age_(0), _weight_(0), _height_(0){}
Baby(int age) :_name_("Unknown"), _age_(age), _weight_(0), _height_(0) {}
// ...省略100个构造函数
// 采取先默认构造,再在构造函数中赋值,有机会去除这类重复代码。
Baby(const std::string name){
init(name, 0, 0, 0);
}
Baby(int age){
init("Unknown", age, 0, 0);
}
// ...省略100个构造函数
void init(const std::string& name, int age, int weight, int height)
{
_name_ = name;
_age_ = age;
_weight_ = weight;
_height_ = height;
}
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
传统的,在构造函数函数体里面进行初始化,实际上是先对变量进行声明,而后赋值。而列表初始化,是直接对变量进行定义。效率更高。
委托构造函数
如果构造函数需要更多的重构,写起来会很麻烦,C++11 允许我们将这些重构为托给一个构造函数
class Baby
{
public:
Baby(const std::string& name, int age, int weight, int height) :
_name_(name), _age_(age), _weight_(weight), _height_(height) {}
Baby(const std::string name) : Baby(name, 0, 0, 0) {} // 委托构造函数方式
Baby(int age) : Baby("Unknown", age, 0, 0) {} // 委托构造函数方式
// ...省略100个构造函数
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
定义对象时使用列表初始化
在 C++11 中,类可以如同结构体一般,在定义对象时使用列表进行初始化。前提是我们的构造函数中有相对应的方法。
class Baby
{
public:
Baby(const std::string& name, int age, int weight, int height) :
_name_(name), _age_(age), _weight_(weight), _height_(height) {}
private:
std::string _name_;
int _age_;
int _weight_;
int _height_;
};
int main()
{
Baby baby = {"name", 10, 10, 10}; // 复制列表初始化
Baby baby {"name", 10, 10, 10}; // 列表初始化
}
当构造函数没有被 explicit 修饰时,复制列表初始化与列表初始化都是合法的,但是当构造函数被 explicit 修饰时,被修饰的构造函数的类,不能发生相应的隐式类型转换,此时最好使用列表初始化而不使用复制列表初始化。
另外,类中成员变量的初始化顺序取决于他们在类中被声明的顺序。
友元可以访问类的私有变量
class Baby
{
private:
std::string baby_name;
int baby_age;
double baby_weight;
public:
Baby(const std::string & _baby_name, const int _baby_age, const double _baby_weight):baby_name(_baby_name), baby_age(_baby_age), baby_weight(_baby_weight){}
inline void showName() const {std::cout<<"Name: "<<baby_name<<std::endl;}
inline void showAge() const {std::cout<<"Age: "<< baby_age<<std::endl;}
inline void showWeight() const {std::cout<<"Weight: "<<baby_weight<<std::endl;}
inline void showAll() const {showName();showAge();showWeight();}
friend std::ostream & operator<<(std::ostream & os, const Baby & baby); // 友元声明
};
std::ostream & operator<<(std::ostream & os, const Baby & baby) // 友元定义
{
os<<"Name: " <<baby.baby_name <<std::endl // 友元使用了私有变量
<<"Age: " <<baby.baby_age <<std::endl // 友元使用了私有变量
<<"Weight: " <<baby.baby_weight <<std::endl; // 友元使用了私有变量
return os;
}
int main()
{
Baby baby = {"name", 2, 15};
baby.showAll(); // 打印全部信息
std::cout<<baby; // 打印全部信息
return 0;
}
示例中,类可以通过他自己的公共方法 showAll 来打印信息,也可以通过友元重载 << 运算符来打印信息。在友元的定义中,我们访问了类的私有变量。友元可以访问类的私有变量。
标签:初始化,const,name,int,age,基础,C++,Baby From: https://www.cnblogs.com/torch-hxm/p/17796360.html