布尔类型是表示布尔量的数据类型,其值只有真(true)和假(false)两个值,布尔类型的数据占1个字节的存储空间。
实现此案例需要按照如下步骤进行。
步骤一:布尔类型
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
bool b;
b = true;
b = false;
std::cout<<std::boolalpha<< b <<std::endl;
std::cout<<sizeof(bool) <<std::endl;
b = 5;
b = 5.5;
b = 'a';
std::cout<<std::boolalpha<< b <<std::endl;
return0;
}
上述代码中,以下代码:
bool b; b = true; b = false;
定义了布尔类型变量b,并将其赋值为true和false。
上述代码中,以下代码:
std::cout<<sizeof(bool) <<std::endl;
从运行结果可以看出,布尔类型占1个字节的存储空间。
上述代码中,以下代码:
b = 5; b = 5.5; b = 'a';
表示任何基本数据类型的数据均可直接复制给布尔变量b。
本案例中的完整代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
bool b;
b = true;
b = false;
std::cout<<std::boolalpha<< b <<std::endl;
std::cout<<sizeof(bool) <<std::endl;
b = 5;
b = 5.5;
b = 'a';
std::cout<<std::boolalpha<< b <<std::endl;
return0;
}
同一作用域内,一组具有相同函数名,不同参数列表的函数,构成重载关系,这组名称相同的函数成为重载函数。重载函数通常完成的功能相近,这样做的好处是减少了函数名的数量,提供了程序的可读性。
实现此案例需要按照如下步骤进行。
步骤一:重载关系
代码如下:
#include <iostream>
void print(void)
{
std::cout<<"call print function"<<std::endl;
}
void print(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
void print(double d)
{
std::cout<<"d = "<< d <<std::endl;
}
void print(int* p)
{
std::cout<<"*p = "<< *p <<std::endl;
}
int main(int argc, constchar * argv[])
{
print();
print(10);
print(10.32);
int n = 100;
print(&n);
return0;
}
上述代码中,以下代码:
void print(void)
{
std::cout<<"call print function"<<std::endl;
}
void print(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
void print(double d)
{
std::cout<<"d = "<< d <<std::endl;
}
void print(int* p)
{
std::cout<<"*p = "<< *p <<std::endl;
}
定义了一组函数名为print的函数,但这些函数的参数均不相同,这就使它们构成了重载关系,相互称为重载函数。虽然只有一个函数名,但却是四个不同的函数。
注意:参数相同仅返回值不同的两个函数不构成重载关系。
代码如下所示:
void print(void)
{
std::cout<<"call print function"<<std::endl;
}
int print(void)
{
std::cout<<"call print function"<<std::endl;
return1;
}
上述代码将报错,print函数重定义。
步骤二:同一作用域内的函数才构成重载关系
代码如下:
void foo (void)
{
}
namespace ns1 {
void foo (int a)
{
}
namespace ns2 {
void foo (int a, int b)
{
}
void bar (void)
{
foo (10, 20);
}
}
void hum (void)
{
foo (30);
}
}
void fun (void)
{
foo ();
}
上述代码中有三个同名的foo函数,它们的参数也不相同,但他们不构成重载关系,因为他们分属三个不同的名字空间,在不同的作用域中。
本案例的完整代码如下所示:
#include <iostream>
void print(void)
{
std::cout<<"call print function"<<std::endl;
}
void print(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
void print(double d)
{
std::cout<<"d = "<< d <<std::endl;
}
void print(int* p)
{
std::cout<<"*p = "<< *p <<std::endl;
}
void foo (void)
{
}
namespace ns1 {
void foo (int a)
{
}
namespace ns2 {
void foo (int a, int b)
{
}
void bar (void)
{
foo (10, 20);
}
}
void hum (void)
{
foo (30);
}
}
void fun (void)
{
foo ();
}
int main(int argc, constchar * argv[])
{
print();
print(10);
print(10.32);
int n = 100;
print(&n);
return0;
}
重载是通过C++换名实现的,换名机制限制了C和C++模块之间的交叉引用。为了能够让C++编译器按照C方式处理函数接口,可以使用extern关键字实现。
实现此案例需要按照如下步骤进行。
步骤一:C形式的调用规格
代码如下所示:
extern"C"
{
void printChar(char c)
{
std::cout<<"c = "<< c <<std::endl;
}
void printInt(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
}
int main(int argc, constchar * argv[])
{
printChar('a');
printInt(10);
return0;
}
上述代码中,以下代码:
extern"C"
{
void printChar(char c)
{
std::cout<<"c = "<< c <<std::endl;
}
void printInt(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
}
表示要求C++编译器按照C方式处理函数接口,即不做换名。由于无法执行换名操作,当然也就无法重载,所以需要用不同的函数名区分相似功能函数。
换名操作实际上就是在编译时,将匹配好的重载函数重新命名的方法。实际上,在编译后重载函数的函数名还是不相同的。
本案例的完整代码如下所示:
extern"C"
{
void printChar(char c)
{
std::cout<<"c = "<< c <<std::endl;
}
void printInt(int n)
{
std::cout<<"n = "<< n <<std::endl;
}
}
int main(int argc, constchar * argv[])
{
printChar('a');
printInt(10);
return0;
}
函数的缺省参数是指在定义函数的时候,给函数形参一个缺省值,当调用该函数的时后,若未给出实参,则与该实参相对应的形参取缺省值。函数的缺省参数是在编译阶段解决的,因此只能用常量、常量表达式或者全局变量等非局部化数值作为缺省值。
实现此案例需要按照如下步骤进行。
步骤一:函数的缺省参数
代码如下所示:
#include <iostream>
void foo(int a, int b = 456)
{
std::cout<<"a = "<< a <<std::endl;
std::cout<<"b = "<< b <<std::endl;
}
int main(int argc, constchar * argv[])
{
foo(100, 200);
foo(300);
return0;
}
上述代码中,以下代码:
void foo(int a, int b = 456)
{
std::cout<<"a = "<< a <<std::endl;
std::cout<<"b = "<< b <<std::endl;
}
定义了一个函数foo,该函数有两个形参,第二个形参的后面有一个数值456,它就是缺省参数。
注意:
缺省参数只能是常量、常量表达式或者全局变量,如下代码是错误的:
void foo(int a,int b = a);
带缺省参数的形参b被定义成局部变量形参a的值了。
上述代码中,以下代码:
foo(100, 200);
在调用函数foo时,对于带缺省参数的形参位置可以像以前一样定义实参,这样,缺省参数将变得无效,实参200被赋值给形参。
上述代码中,以下代码:
foo(300);
在调用函数foo时,对于带缺省参数的形参位置也可以不写任何实参值,这样,缺省参数将起作用,相当于把实参456被赋值给形参。
本案例的完整代码如下所示:
#include <iostream>
void foo(int a, int b = 456)
{
std::cout<<"a = "<< a <<std::endl;
std::cout<<"b = "<< b <<std::endl;
}
int main(int argc, constchar * argv[])
{
foo(100, 200);
foo(300);
return0;
}
new和delete是C++提供的两个运算符,分别用于动态内存的分配和释放。new相当于C语言中的malloc函数,delete相当于C语言中的free函数。
实现此案例需要按照如下步骤进行。
步骤一:动态内存分配
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
return0;
}
上述代码中,以下代码:
int *p = newint;
为整型指针变量p分配4个字节的存储空间。
上述代码中,以下代码:
delete p;
将指针p所指向的存储空间释放掉。
上述代码中,以下代码:
p = newint(100);
为整型指针变量p分配4个字节的存储空间,同时将新分配的存储空间初始化为整数100。
步骤二:不能与C语言中的动态内存分配函数混用
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
return0;
}
上述代码中,以下代码:
p = newint; free(p); p = (int*)malloc(sizeof(int)); delete p;
是不建议使用的方法,它会带来不可预知的问题。
步骤三:数组的分配与释放
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
p = newint [4] {10, 20, 30, 40};
for (int i = 0; i <4; i++)
std::cout<< p[i] <<' ';
std::cout<<std::endl;
delete[] p;
int (*row) [4] = newint [3][4];
row[1][2] = 15;
delete[] row;
return0;
}
上述代码中,以下代码:
p = newint [4] {10, 20, 30, 40};
为整型指针变量p分配4个整型变量所占的存储空间,即4*4 = 16个字节。这样相当于分配了一个整型数组。用new操作符动态分配数组时,会在数组首元素前面多分配4或8个字节,用以存放数组的长度。
上述代码中,以下代码:
delete[] p;
将分配的16个字节的存储空间释放。注意此时一定不要忘记中括号[]。
上述代码中,以下代码:
int (*row) [4] = newint [3][4];
可以分配多维数组,但需要注意的是,高维数组释放时,依然使用如下语句:
delete[] row;
步骤四:野指针和空指针
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
p = newint [4] {10, 20, 30, 40};
for (int i = 0; i <4; i++)
std::cout<< p[i] <<' ';
std::cout<<std::endl;
delete[] p;
int (*row) [4] = newint [3][4];
row[1][2] = 15;
delete[] row;
int *p1 = newint;
*p1 = 200;
delete p1;
delete p1;
int *p2;
delete p2;
int *p3 = NULL;
delete p3;
return0;
}
上述代码中,以下代码:
int *p1 = newint; *p1 = 200; delete p1; delete p1;
的最后一行,重复释放p1。因为倒数第二行释放后,p1已经变成野指针,释放野指针会导致程序崩溃。
上述代码中,以下代码:
int *p2; delete p2;
指针p2定义时没有初始化,p2也是野指针。
上述代码中,以下代码:
int *p3 = NULL; delete p3;
不会崩溃,因为delete运算符对空指针不作任何操作。
步骤五:内存分配失败
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
p = newint [4] {10, 20, 30, 40};
for (int i = 0; i <4; i++)
std::cout<< p[i] <<' ';
std::cout<<std::endl;
delete[] p;
int (*row) [4] = newint [3][4];
row[1][2] = 15;
delete[] row;
int *p1 = newint;
*p1 = 200;
delete p1;
//delete p1;
int *p2;
//delete p2;
int *p3 = NULL;
delete p3;
try {
char* p = newchar[0xFFFFFFFF];
p[0] = 'a';
delete p;
}
catch (std::bad_alloc& ex) {
std::cerr<<"内存分配失败!"<< std::endl;
exit (-1);
}
return0;
}
上述代码中,以下代码:
try {
char* p = newchar[0xFFFFFFFF];
}
catch (std::bad_alloc& ex) {
std::cerr<<"内存分配失败!"<< std::endl;
exit (-1);
}
当使用new分配内存失败时,将抛出异常。
步骤六:定位分配
代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
p = newint [4] {10, 20, 30, 40};
for (int i = 0; i <4; i++)
std::cout<< p[i] <<' ';
std::cout<<std::endl;
delete[] p;
int (*row) [4] = newint [3][4];
row[1][2] = 15;
delete[] row;
int *p1 = newint;
*p1 = 200;
delete p1;
//delete p1;
int *p2;
//delete p2;
int *p3 = NULL;
delete p3;
try {
char* p = newchar[0xFFFFFFFF];
p[0] = 'a';
delete p;
}
catch (std::bad_alloc& ex) {
std::cerr<<"内存分配失败!"<< std::endl;
exit (-1);
}
char* pool = newchar[1024]; // 分配内存池
int* pn = new (pool) int (123);
char* ps = new (pool + 4) char[15];
strcpy (ps, "Hello, World !");
double* pd = new (pool + 19) double (3.14);
std::cout<< *pn <<std::endl; // 123
std::cout<< ps <<std::endl; // Hello, World !
std::cout<< *pd<<std::endl; // 3.14
delete[] pool; // 释放内存池
return0;
}
上述代码中,以下代码:
char* pool = newchar[1024]; // 分配内存池
分配了一个由1024个元素的字符数组,作为内存池使用。
上述代码中,以下代码:
int* pn = new (pool) int (123);
在内存池中分配4个字节作为一个整型变量使用。
上述代码中,以下代码:
char* ps = new (pool + 4) char[15];
在内存池中分配15个字节作为一个字符型数组使用。值得注意的是pool + 4是从内存池的第5个字节开始分配,否则上面分配的整型变量将被覆盖。
上述代码中,以下代码:
delete[] pool; // 释放内存池
在内存池中分配的变量或数组无需释放,只要最后一次性释放整个内存池即可。
本案例的完整代码如下所示:
#include <iostream>
int main(int argc, constchar * argv[])
{
int *p = newint;
*p = 10;
std::cout<< *p <<std::endl;
delete p;
p = newint(100);
std::cout<< *p <<std::endl;
delete p;
p = newint;
free(p);
p = (int*)malloc(sizeof(int));
delete p;
p = newint [4] {10, 20, 30, 40};
for (int i = 0; i <4; i++)
std::cout<< p[i] <<' ';
std::cout<<std::endl;
delete[] p;
int (*row) [4] = newint [3][4];
row[1][2] = 15;
delete[] row;
int *p1 = newint;
*p1 = 200;
delete p1;
//delete p1;
int *p2;
//delete p2;
int *p3 = NULL;
delete p3;
try {
char* p = newchar[0xFFFFFFFF];
p[0] = 'a';
delete p;
}
catch (std::bad_alloc& ex) {
std::cerr<<"内存分配失败!"<< std::endl;
exit (-1);
}
char* pool = newchar[1024]; // 分配内存池
int* pn = new (pool) int (123);
char* ps = new (pool + 4) char[15];
strcpy (ps, "Hello, World !");
double* pd = new (pool + 19) double (3.14);
std::cout<< *pn <<std::endl; // 123
std::cout<< ps <<std::endl; // Hello, World !
std::cout<< *pd<<std::endl; // 3.14
delete[] pool; // 释放内存池
return0;
}