当前仅显示指定条件回帖 [ 展开查看全部 ]
文件名称:
README.md
所在目录:
3.C++程序设计 / week3
文件大小:
7.26 KB
下载地址:
文本预览:
# Week3 类和对象
## 内联成员函数和重载成员函数
- inline + 成员函数名
- 整个函数体写在类定义内部
```c++
class B
{
inline void func1();
void func2()
{
...
};
};
void B::func1(){}
```
成员函数可以重载,也可以带缺省参数
## 构造函数
成员函数的一种
- 名字与类名相同,可以有参数,不能有返回值(void也不行)
- 作用是对对象进行初始化,如给成员变量赋初值
- 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
- 默认构造函数无参数,不做任何操作
可以有多个构造函数,参数个数或类型不同
```c++
Complex(double r, double i );
Complex (double r );
Complex (Complex c1, Complex c2);
```
构造函数最好是public的,private构造函数 不能直接用来初始化对象
## 复制构造函数
只有一个参数,既对同类对象的引用
- `X::X( X &)`
- `X::X(const X &)`
没有定义,编译器会自动生成。如果定义了,默认的就不存在。
### 使用的三种情况
- 用一个对象去**初始化**同类的另一个对象(不适用于赋值!)
```c++
Complex c2(c1);
Complex c2 = c1;
```
- 如果某函数有一个参数是类 A 的对象,那么该函数被调用时,类A的复制构造函数将被调用。(即形参用构造函数初始化,这时**形参和实参就不一定相等**了!)
- 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用。(这时**返回值也不一定与返回对象相等**!)
## 类型转换构造函数
目的:
- 实现类型的自动转换
特点:
- 只有一个参数
- 不是复制构造函数
编译系统会自动调用转换构造函数
- 建立一个临时对象/临时变量
```c++
class Complex
{
public:
double real, imag;
Complex(double r, double i)
{
real = r;
imag = i;
}
Complex(int i)
{
real = i;
imag = 0;
cout << "IntConstructor called" << endl;
}
};
int main()
{
Complex c1(7, 8);
Complex c2 = 12; // 初始化
c1 = 9; // 赋值,9被自动转换成一个临时的Complex对象
cout << c1.real << "+" << c1.imag << "i" << endl;
return 0;
}
```
## 析构函数
成员函数的一种
- 名字与类名相同
- 在前面加`~`
- 没有参数和返回值
- 一个类最多只有一个析构函数
对象消亡时自动调用析构函数,在对象消亡前做善后工作,释放动态分配的空间等等
定义类时没写析构函数, 则编译器生成缺省析构函数,但不涉及释放用户申请的内存释放等清理工作
## 静态成员变量和静态成员函数
静态成员:在说明前面加了`static`关键字的成员。
- 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
> `sizeof` 运算符不会计算静态成员变量。 静态成员变量放在所有对象的外部
普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用与某个对象。
因此静态成员**不需要通过对象**就能访问。
- `类名::成员名`:`CRectangle::PrintTotal(); `
- `对象名.成员名`:`CRectangle r; r.PrintTotal(); `
- `指针->成员名`:`CRectangle * p = &r; p->PrintTotal(); `
- `引用.成员名`:`CRectangle & ref = r; int n = ref.nTotalNumber; `
静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在静态成员函数本质上是全局函数,设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一个整体,易于维护和理解。
注意:
- 静态成员变量需要在类外部特别声明初始化:`int CRectangle::nTotalNumber = 0; `
- 在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数。(原因,不知道作用于哪个对象)
## 成员对象和封闭类
成员对象: 一个类的成员变量是另一个类的对象
包含成员对象的类叫封闭类 (Enclosing)
封闭类一定要自己定义构造函数,可以利用初始化列表方便的定义构造函数
### 初始化列表
```c++
类名::构造函数(参数表):成员变量1(参数表), 成员变量2(参数表), …
{
…
}
```
成员对象初始化列表中的参数
- 任意复杂的表达式
- 函数 / 变量/ 表达式中的函数,变量有定义
### 调用顺序
当封闭类对象生成时:
- S1: 执行所有成员对象的构造函数
- S2: 执行封闭类的构造函数
成员对象的构造函数调用顺序:
- 和成员对象在类中的说明顺序一致
- 与在成员初始化列表中出现的顺序无关
当封闭类的对象消亡时:
- S1: 先执行封闭类的析构函数
- S2: 执行成员对象的析构函数
析构函数顺序和构造函数的调用顺序相反
## 友元
### 友元函数
一个类的友元函数可以访问该类的私有成员
### 友元类
A是B的友元类 $\rightarrow$ A的成员函数可以访问B的私有成员
友元类之间的关系不能传递,不能继承
## `this`指针
起源:C++程序翻译为C程序示例
```c++
class CCar
{
public:
int price;
void SetPrice(int p);
};
void CCar::SetPrice(int p)
{
price = p;
}
int main()
{
CCar car;
car.SetPrice(20000);
return 0;
}
```
```c
struct CCar
{
int price;
};
void SetPrice(struct CCar *this, int p)
{
this->price = p;
}
int main()
{
struct CCar car;
SetPrice(&car, 20000);
return 0;
}
```
`this` 指针的作用:其作用就是指向成员函数所作用的对象,例:
```c++
Complex AddOne()
{
this->real++;
return *this;
}
```
```c++
class A
{
int i;
public:
void Hello() { cout << "hello" << endl; }
// 相当于 void Hello(A * this ) { cout << "hello" << endl; }
// 如果是 void Hello() { cout << i << "hello" << endl; } 就出错
};
int main()
{
A *p = NULL;
p->Hello();
Hello(p);
} // 输出:hello
```
静态成员函数中不能使用 this 指针! 因为静态成员函数并不具体作用与某个对象! 因此,静态成员函数的真实的参数的个数,就是程序中写出的参数个数!
## 常量对象、常量成员函数、常引用
### 常量对象
如果不希望某个对象的值被改变,则定义该对象的时候可以在**前面**加 `const` 关键字。
- 不能修改常量对象的值
- 不能调用非常量成员函数
```c++
const class instance;
```
### 常量成员函数
在类的成员函数说明**后面**可以加`const`关键字,则 该成员函数成为常量成员函数。
常量成员函数执行期间不应修改其所作用的对象 。因此,在常量成员函数中:
- 不能修改成员变量的值 (静态成员变量除外)
- 也不能调用同类的非常量成员函数(静态成员函数除外)。
常量成员函数的重载:两个成员函数,名字和参数表都一样,但是一个 是`const`,一个不是,算重载。
### 常引用
引用前面可以加`const`关键字,成为常引用。 不能通过常引用,修改其引用的变量。
为了减少形参调用复制构造函数的开销,可以使用对象的引用做参数
```c++
class Sample
{
...
};
void PrintObj(const Sample &o)
{
...
}
```
## 内联成员函数和重载成员函数
- inline + 成员函数名
- 整个函数体写在类定义内部
```c++
class B
{
inline void func1();
void func2()
{
...
};
};
void B::func1(){}
```
成员函数可以重载,也可以带缺省参数
## 构造函数
成员函数的一种
- 名字与类名相同,可以有参数,不能有返回值(void也不行)
- 作用是对对象进行初始化,如给成员变量赋初值
- 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
- 默认构造函数无参数,不做任何操作
可以有多个构造函数,参数个数或类型不同
```c++
Complex(double r, double i );
Complex (double r );
Complex (Complex c1, Complex c2);
```
构造函数最好是public的,private构造函数 不能直接用来初始化对象
## 复制构造函数
只有一个参数,既对同类对象的引用
- `X::X( X &)`
- `X::X(const X &)`
没有定义,编译器会自动生成。如果定义了,默认的就不存在。
### 使用的三种情况
- 用一个对象去**初始化**同类的另一个对象(不适用于赋值!)
```c++
Complex c2(c1);
Complex c2 = c1;
```
- 如果某函数有一个参数是类 A 的对象,那么该函数被调用时,类A的复制构造函数将被调用。(即形参用构造函数初始化,这时**形参和实参就不一定相等**了!)
- 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用。(这时**返回值也不一定与返回对象相等**!)
## 类型转换构造函数
目的:
- 实现类型的自动转换
特点:
- 只有一个参数
- 不是复制构造函数
编译系统会自动调用转换构造函数
- 建立一个临时对象/临时变量
```c++
class Complex
{
public:
double real, imag;
Complex(double r, double i)
{
real = r;
imag = i;
}
Complex(int i)
{
real = i;
imag = 0;
cout << "IntConstructor called" << endl;
}
};
int main()
{
Complex c1(7, 8);
Complex c2 = 12; // 初始化
c1 = 9; // 赋值,9被自动转换成一个临时的Complex对象
cout << c1.real << "+" << c1.imag << "i" << endl;
return 0;
}
```
## 析构函数
成员函数的一种
- 名字与类名相同
- 在前面加`~`
- 没有参数和返回值
- 一个类最多只有一个析构函数
对象消亡时自动调用析构函数,在对象消亡前做善后工作,释放动态分配的空间等等
定义类时没写析构函数, 则编译器生成缺省析构函数,但不涉及释放用户申请的内存释放等清理工作
## 静态成员变量和静态成员函数
静态成员:在说明前面加了`static`关键字的成员。
- 普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
> `sizeof` 运算符不会计算静态成员变量。 静态成员变量放在所有对象的外部
普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用与某个对象。
因此静态成员**不需要通过对象**就能访问。
- `类名::成员名`:`CRectangle::PrintTotal(); `
- `对象名.成员名`:`CRectangle r; r.PrintTotal(); `
- `指针->成员名`:`CRectangle * p = &r; p->PrintTotal(); `
- `引用.成员名`:`CRectangle & ref = r; int n = ref.nTotalNumber; `
静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在静态成员函数本质上是全局函数,设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一个整体,易于维护和理解。
注意:
- 静态成员变量需要在类外部特别声明初始化:`int CRectangle::nTotalNumber = 0; `
- 在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数。(原因,不知道作用于哪个对象)
## 成员对象和封闭类
成员对象: 一个类的成员变量是另一个类的对象
包含成员对象的类叫封闭类 (Enclosing)
封闭类一定要自己定义构造函数,可以利用初始化列表方便的定义构造函数
### 初始化列表
```c++
类名::构造函数(参数表):成员变量1(参数表), 成员变量2(参数表), …
{
…
}
```
成员对象初始化列表中的参数
- 任意复杂的表达式
- 函数 / 变量/ 表达式中的函数,变量有定义
### 调用顺序
当封闭类对象生成时:
- S1: 执行所有成员对象的构造函数
- S2: 执行封闭类的构造函数
成员对象的构造函数调用顺序:
- 和成员对象在类中的说明顺序一致
- 与在成员初始化列表中出现的顺序无关
当封闭类的对象消亡时:
- S1: 先执行封闭类的析构函数
- S2: 执行成员对象的析构函数
析构函数顺序和构造函数的调用顺序相反
## 友元
### 友元函数
一个类的友元函数可以访问该类的私有成员
### 友元类
A是B的友元类 $\rightarrow$ A的成员函数可以访问B的私有成员
友元类之间的关系不能传递,不能继承
## `this`指针
起源:C++程序翻译为C程序示例
```c++
class CCar
{
public:
int price;
void SetPrice(int p);
};
void CCar::SetPrice(int p)
{
price = p;
}
int main()
{
CCar car;
car.SetPrice(20000);
return 0;
}
```
```c
struct CCar
{
int price;
};
void SetPrice(struct CCar *this, int p)
{
this->price = p;
}
int main()
{
struct CCar car;
SetPrice(&car, 20000);
return 0;
}
```
`this` 指针的作用:其作用就是指向成员函数所作用的对象,例:
```c++
Complex AddOne()
{
this->real++;
return *this;
}
```
```c++
class A
{
int i;
public:
void Hello() { cout << "hello" << endl; }
// 相当于 void Hello(A * this ) { cout << "hello" << endl; }
// 如果是 void Hello() { cout << i << "hello" << endl; } 就出错
};
int main()
{
A *p = NULL;
p->Hello();
Hello(p);
} // 输出:hello
```
静态成员函数中不能使用 this 指针! 因为静态成员函数并不具体作用与某个对象! 因此,静态成员函数的真实的参数的个数,就是程序中写出的参数个数!
## 常量对象、常量成员函数、常引用
### 常量对象
如果不希望某个对象的值被改变,则定义该对象的时候可以在**前面**加 `const` 关键字。
- 不能修改常量对象的值
- 不能调用非常量成员函数
```c++
const class instance;
```
### 常量成员函数
在类的成员函数说明**后面**可以加`const`关键字,则 该成员函数成为常量成员函数。
常量成员函数执行期间不应修改其所作用的对象 。因此,在常量成员函数中:
- 不能修改成员变量的值 (静态成员变量除外)
- 也不能调用同类的非常量成员函数(静态成员函数除外)。
常量成员函数的重载:两个成员函数,名字和参数表都一样,但是一个 是`const`,一个不是,算重载。
### 常引用
引用前面可以加`const`关键字,成为常引用。 不能通过常引用,修改其引用的变量。
为了减少形参调用复制构造函数的开销,可以使用对象的引用做参数
```c++
class Sample
{
...
};
void PrintObj(const Sample &o)
{
...
}
```
点赞
回复
X