本博文是根据上的内容归纳汇总而得。
2. 名字空间
名字空间的定义
名字空间除了系统定义的名字空间之外,还可以自己定义,定义名字空间用关键字“namespace”,使用名字空间时用符号“::”指定。
-
不指定名字空间的变量或函数都是当前名字空间下的变量或函数。
-
不定义名字空间的情况下,都属于全局名字空间。
-
同一个名字空间可以定义多次。
-
#include <iostream>
-
using namespace std;
-
namespace na
-
{
-
void print(int n) { //与名字空间nb的函数名相同
-
cout << "na::print: " << n << endl;
-
}
-
}
-
namespace nb
-
{
-
void print(int n) { //与名字空间na的函数名相同
-
cout << "nb::print: " << n << endl;
-
}
-
}
-
namespace na // 同一个名字空间可以定义多次
-
{
-
void print2(int a, int b) {
-
print(a);
-
print(b);
-
}
-
}
-
int main ( )
-
{
-
na::print(3); // 指定na下的print函数
-
nb::print(4); // 指定na下的print函数
-
na::print2(5, 6); // 指定na下的print2函数
-
return 0;
-
}
运行结果:
na::print: 3
nb::print: 4
na::print: 5
na::print: 6
3. 引用
引用(reference)”与指针象似但不是指针。引用主要有3种用法:
-
单独使用(一般称为“独立引用”);
-
作参数使用;
-
作返回值使用。
独立引用
从功能上来说,引用型变量又可以看做事被引用变量的“别名”,这两个变量只是名称不同,变量的地址是同一个(共用体中的元素也是一样)。使用“引用”的好处主要是可以“逆向引用”。定义独立引用时需要注意以下规则:
-
引用型变量在定义时必须初始化。
-
被引用的对象必须已经分配了空间,即不能为空,或空指针。
-
被引用的对象不能为地址,即指针变量、数组变量等不能被引用。
-
-
#include <iostream>
-
using namespace std;
-
int main( )
-
{
-
int a ; //
-
int &b = a; //b和a实际上是同一变量
-
b = 100; //b赋值为100,也就是a赋值为100
-
int c = b; // c和b的地址不一样
-
cout << a << endl;
-
//a的地址和b的地址应该是完全一样,但是c的有别于a和b
-
cout << &a << endl;
-
cout << &b << endl;
-
cout << &c << endl;
-
/*-------▼下面代码有错,注释后才能运行▼-----------
-
int x[] = {12,15,20} ;
-
int &y = x; //错误:数组、指针不能被引用
-
int x1;
-
int &y1; //错误:引用时必须初始化
-
y1 = x1;
-
-------▲上面代码有错,注释后才能运行▲-----------*/
-
return 0;
-
}
输出结果:
100
0x7fff2b0bb4b4
0x7fff2b0bb4b4
0x7fff2b0bb4b0
函数的参数引用
许多教程在讲解参数引用时都喜欢选择交换两参数内容的swap(int &x, int &y)函数作例子,这的确很容易说明清楚,但并不能说这种用法优于指针作参数。
-
#include <iostream>
-
using namespace std;
-
//|右边为指针作参数的代码,仅作比较用。
-
void swap(int &x, int &y); //|void swap(int *x, int *y);
-
//|
-
int main ( ) //|
-
{ //|
-
int i = 12; //|
-
int j = 25; //|
-
cout << "i=" << i << " j=" << j << endl; //|
-
//|
-
swap(i, j); //|swap(&i, &j);
-
cout << "i=" << i << " j=" << j << endl; //|
-
//|
-
return 0; //|
-
} //|
-
//|
-
void swap(int &x, int &y) //|void swap(int *x, int *y)
-
{ //|{
-
int t; //| int t;
-
//|
-
t = x; //| t = *x;
-
x = y; //| *x = *y;
-
y = t; //| *y = *x;
-
}
运行结果:
i=12 j=25
i=25 j=12
4. 类和对象
类、实例和对象
类是从C语言中的结构体演变而来,结构体的成员变量也就演化成类的成员变量,这时类只能存放数据。为了在类内部操纵这些数据,增加了成员函数的功能。所谓成员函数就是在类的内部定义,用来操作类的成员变量的函数。随后对成员变量和成员函数附上“私有”、“保护”和“公共”的访问权限,于是“类”便大致成型。事实上,C++中结构体的功能大致和类相当,也有了成员函数。“成员”是成员变量和成员函数的统称。
“类”和结构体一样,是一种自定义的数据类型,但不是基本类型。“实例”是用自己定义的“类”这个数据类型来定义的变量。这些一个一个的实例统称“对象”。另外,“继承”和“派生”是同一件事的不同说法,B类继承了A类,也就是说A类派生了B类。
class 类名 { //| class CSample {
访问符: //| public:
成员变量定义; //| int x1;
成员函数定义; //| CSample();
访问符: //| protected:
成员变量定义; //| int a;
成员函数定义; //| float sum(float f1, float f2);
访问符: //| private:
成员变量定义; //| int m;
成员函数定义; //| double sum(double f1, double f2);
...... //| ......
} //| }
一般按习惯将private:定义部分放在紧靠类名下面,并且“private:”可以省略。“private:”下面定义的成员全是“私有”的,也就是只能在这个类的成员函数里可以使用,外部(包括派生的子类)不能使用。“public:”下面定义的成员,所有地方都能使用。“protected:”下面定义的成员,在派生的子类中则相当于“public”,其它地方则相当于“private”。
构造函数和析构函数
“构造函数”是类产生实例时被调用,进行初始化设置,是一个特殊的成员函数,函数名与类名相同,没有返回值。一般构造函数定义在“public:”下面,如上述的CSample(),但有时为了阻止多个实例的产生而特意定义在“private:”或“protected:”下面。当初始化时没有什么需要设定时也可以不定义,编译时会自动生成一个默认的构造函数。构造函数的重载使得实例的生成灵活而且方便,默认的构造函数没有参数,且是定义在“public:”下面的。
“析构函数”是类的实例被销毁时调用,进行最后的处理,例如释放动态分配的内存等。一般析构函数定义在“public:”下面,不需要时也可以不定义,编译时会自动生成一个默认的析构函数。析构函数的函数名与类名相同,前面有“~”返回值。
下面的例子演示构造函数和析构函数被调用的顺序。
-
#include <iostream>
-
using namespace std;
-
class CA {
-
int a;
-
public:
-
CA(){
-
a = 0;
-
cout << "构造函数: " << a << endl;
-
}
-
~CA(){
-
cout << "析构函数: " << a << endl;
-
}
-
void setA(int x) {
-
a = x;
-
}
-
void print() {
-
cout << "print: " << a << endl;
-
}
-
};
-
int main ( )
-
{
-
CA ca;
-
//ca.a = 10; //成员变量a是私有的,不能直接访问
-
ca.setA(10);
-
ca.print();
-
return 0;
-
}
运行结果:
构造函数:0
print:10
析构函数:10
生成实例的3种方法
了解生成实例的三种方法的细微区别是很重要的:
-
申明为变量;
-
从无名对象复制;
-
申明为指针并动态生成。
注意:指针的成员用“->”,而不用“.”。
-
#include <iostream>
-
#include <string>
-
using namespace std;
-
int main ( )
-
{
-
string strA("C语言中文网"); //直接调用构造函数生成实例
-
cout << strA << " " << strA.length() << endl;
-
string strB; //先调用构造函数生成空字符串实例
-
strB = string("C++60分钟入门教程"); //再调用构造函数生成无名实例,然后复制给strB实例,无名实例立即销毁
-
cout << strB << " " << strB.length() << endl; //这和上面①的方法的结果相同
-
string *strC; //先定义一个指针,尚未分配空间
-
//动态调用构造函数生成实例后,再将实例地址赋给指针变量
-
strC = new string("");
-
cout << *strC << " " << strC->length() << endl;
-
delete strC; //千万不要忘记释放
-
return 0;
-
}
运行结果:
C语言中文网 11
C++60分钟入门教程 17
49
5. 成员函数和运算符的重载
构造函数的重载
构造函数可以重载,使得生成实例时非常方便。构造函数一般要对成员变量赋初值,有两种写法:
-
#include <iostream>
-
#include <string>
-
using namespace std;
-
class stuff {
-
string name;
-
int age;
-
public:
-
stuff() { //这是写法一
-
cout << name << "---" << age << endl; // age对应的是
-
name = "空";
-
age = 0;
-
cout << name << "---" << age << endl;
-
}
-
stuff(string n, int a):name(n),age(a) //这是写法二
-
{
-
cout << name << "---" << age << endl;
-
}
-
string getName() {
-
return name;
-
}
-
int getAge() {
-
return age;
-
}
-
};
-
int main ( )
-
{
-
stuff st2;
-
stuff st1("C语言中文网", 3);
-
return 0;
-
}
运行结果:
---2817728
空---0
C语言中文网---3
写法一是在构造函数体中赋值,赋值前成员变量已经有了地址空间,尚未有值。写法二是一种特殊方法,是在成员变量分配空间的同时将参数的值赋给成员变量。虽然写法二用的人少,但明显优于写法一。事实上,如果将成员变量的定义改为常量,“const string name;”和“const int age;”,写法一将出错,而写法二仍然正确。
运算符重载
运算符重载对于普通函数和成员函数来说,格式稍有不同。
//单目运算符
成员函数: 返回值类型 operator 运算符 () ;
普通函数: 返回值类型 operator 运算符 (对象的类型) ;
//双目运算符
成员函数: 返回值类型 operator 运算符 (对象的类型) ;
普通函数: 返回值类型 operator 运算符 (对象的类型1, 对象的类型2) ;
//函数调用
成员函数: 返回值类型 operator (任意的参数列) ;
//数组元素
成员函数: 返回值类型 operator[] (参数类型) ;
//增1/减1运算符
成员函数: 返回值类型 operator 运算符 (int) ;
普通函数: 返回值类型 operator 运算符 (对象的类型, int) ;
-
#include <iostream>
-
#include <string>
-
using namespace std;
-
class stuff {
-
string name;
-
int age;
-
public:
-
stuff(string n, int a):name(n),age(a)
-
{
-
cout << name << "---" << age << endl;
-
}
-
string getName() {
-
return name;
-
}
-
int getAge() {
-
return age;
-
}
-
void operator +(int x); //运算符重载的定义
-
void operator +(string s); //运算符重载的定义
-
};
-
void stuff::operator +(int x) //运算符重载的实装
-
{
-
age = age + x;
-
}
-
void stuff::operator +(string s) //运算符重载的实装
-
{
-
name = name + s;
-
}
-
int main ( )
-
{
-
stuff st2("C语言中文网", 3);
-
st2 + 2; //+运算
-
st2 + ".C++ 60分钟入门教程"; //+运算
-
cout << st2.getName() << st2.getAge() << endl;
-
return 0;
-
}
运行结果:
C语言中文网---3
C语言中文网.C++ 60分钟入门教程5
阅读(1523) | 评论(0) | 转发(0) |