02.类和对象
内联成员函数和重载成员函数
- 内联成员函数
inline + 成员函数
- 整个函数体出现在类定义内部
- 重载成员函数
- 成员函数 – 带缺省参数
- 避免缺省参数函数和无参函数的二义性
构造函数
-
一般构造函数
-
复制构造函数
-
只有一个参数, 即对同类对象的引用
-
T :: T(T&)
或T :: T(const T&)
-
若未定义, 编译器生成默认复制构造函数(完成复制功能)
1
2
3
4
5
6class Complex {
private:
double real, imag;
};
Complex c1; //调用缺省无参构造函数
Complex c2(c1); //调用缺省的复制构造函数, 将c2初始化成和c1一样 -
什么时候起作用
-
当用一个对象去初始化同类的另一个对象时
1
2Complex c2(c1);
Complex c2 = c1; //初始化语句, 非赋值语句 -
如果某函数有一个参数是类A的对象, 那么该函数被调用时, 类A的复制构造函数将被调用
1
2
3
4
5
6void Func(A a1){}
int main() {
A a2;
Func(a2);
return 0;
} -
如果函数的返回值是类A的对象时, 则函数返回时, A的复制构造函数被调用
1
2
3
4
5
6
7
8A Func() {
A b(4);
return b; //返回的b未必就是上面定义的b, 取决于A的复制构造函数
}
int main() {
cout << Func().v << endl;
return 0;
}
-
-
-
类型转换构造函数
-
实现类型的自动转换
-
只有一个参数
-
赋值时, 编译系统会自动调用, 建立一个临时对象/临时变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Complex {
public:
double real, imag;
Complex(int i) { //类型转换构造函数
real = i; imag = 0;
}
Complex(double r, double i) {
real = r; imag = i;
}
};
int main() {
Complex c1(7, 8);
Complex c2 = 12; //初始化语句, 调用构造函数
c1 = 9; //赋值语句, 调用类型转换构造函数, 被自动转换成一个临时Complex对象
return 0;
}
-
析构函数
-
没有参数和返回值
-
一个类最多只有一个析构函数
-
对象消亡时自动调用
-
未定义析构函数时, 编译器自动生成一个没用的析构函数
静态成员变量和静态成员函数
-
static
-
静态成员变量所有对象共享
-
sizeof
运算符不会计算静态成员变量1
2
3
4
5class CMyclass {
int n;
static int s;
};
//sizeof(CMyclass) == 4 -
静态成员函数不具体作用于某个对象, 不需要通过对象就能访问
类名::成员名
对象名.成员名
指针->成员名
引用.成员
-
易于理解和维护
-
必须在定义类的文件中对静态成员变量进行一次说明或初始化, 否则编译能通过, 链接不能通过
-
在静态成员函数中, 不能访问非静态成员变量, 也不能调用非静态成员函数
成员对象和封闭类概念
-
成员对象: 一个类的成员变量是另一个类的对象
-
包含成员对象的类叫做封闭类
-
调用顺序
- 当封闭类对象生成时
- 执行所有成员对象的构造函数
- 执行封闭类的构造函数
- 成员对象的构造函数调用顺序
- 和成员对象在类中的说明顺序一致
- 与在成员初始化列表中出现的顺序无关
- 当封闭类的对象消亡时
- 先执行封闭类的析构函数
- 执行成员对象的析构函数
- 当封闭类对象生成时
友元
-
友元函数
-
一个类的友元函数可以访问该类的私有成员
1
2
3
4
5
6
7
8
9
10
11class CCar; //提前声明CCar类, 以便后面CDriver类使用
class CDriver {
public:
void ModifyCar(CCar *pCar); //改装汽车
};
class CCar {
private:
int price;
friend int MostExpensiveCar(CCar cars[], int total); //声明友元
friend void CDriver::ModifyCar(CCar *pCar); //声明友元
};
-
-
友元类
- A是B的友元类, A的成员函数可以访问B的私有成员
- 友元类之间的关系不能传递, 不能继承
this指针
-
非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针
1
2
3
4
5
6
7
8
9
10class A {
int i;
public:
void Hello() { cout << "hello" << endl; }
//编译为 void Hello(A *this) { cout << "hello" << endl; }
};
int main() {
A *p = NULL;
p->Hello(); //编译为 Hello(p);
} //输出: hello
常量对象、常量成员函数和常引用
-
常量成员函数(在函数后面加const)执行期间不应修改其所作用的对象, 因此, 在常量成员函数中不能修改成员变量的值 (静态成员变量除外), 也不能调用同类的非常量成员函数 (静态成员函数除外)
1
2
3
4
5
6
7
8
9
10
11
12
13
14class CTest {
private:
int n;
public:
CTest() { n = 1; }
int GetValue() const { return n; }
int GetValue() { return 2 * n; }
};
int main() {
const CTest objTest1;
CTest objTest2;
cout << objTest1.GetValue() << "," << objTest2.GetValue(); //输出: 1,2
return 0;
} -
常引用
-
对象作为函数的参数时, 生成参数需要调用复制构造函数, 效率比较低, 用指针作参数, 代码不好看
-
可以用对象的引用作为参数, 但是有风险, 函数中修改形参, 实参也会变
1
2
3
4
5
6class Sample {
...
};
void Print(const Sample &o) {
...
}
-