前篇:[C++ 笔记] 类和对象基础
# 代理构造
一个构造函数调用另外一个构造函数:
public: | |
A(): A(0){} | |
A(int i): A(i, 0){} | |
A(int i, int j) | |
{ | |
num1=i; | |
num2=j; | |
average=(num1+num2)/2; | |
} |
一定要避免环形调用,递归调用也是:
// 上段第三个 ctor 改为: | |
A(int i, int j): A(){} | |
// 出现环形调用 omo |
踩坑记录:
#include <iostream> | |
using namespace std; | |
class C | |
{ | |
public: | |
int x; | |
C() | |
{ | |
C(10); | |
} | |
C(int i): x{i} {} | |
}; | |
int main() | |
{ | |
C c; | |
cout << c.x << endl; // 输出不是 10 | |
return 0; | |
} |
加一下高亮:<img src="https://s3.ax1x.com/2021/01/27/sznUyD.png"style="zoom:50%;" /> 这个 C(10);
是一个匿名对象 (⊙x⊙;)
在初始化列表处是调用,在 ctor 内是创建匿名对象 (﹁ ﹁) ~→
# 不可变对象
对象创建后,其内容不可改变,除非通过成员拷贝。不可变对象所属的类称不可变类。
必要条件:
- 所有数据域均为私有属性。
- 无更改器函数。
ex:满足上述不一定是不可变对象, 若存在成员函数 返回 指向私有成员的指针,则可在对象外部修改数据成员。
# 实例成员与静态成员
用关键字 static 声明不绑定到类实例的成员。
- C++17:
constexpr
必须在类中声明并初始化。inline
const
可以在类中声明并初始化。 - 大部分情况必须在类外定义并初始化,且不带
static
关键字。
实例:
#include <iostream> | |
using namespace std; | |
class Square{ | |
private: | |
double side {1.0}; // 实例成员 | |
static int numberOfObjects; // 静态成员 | |
public: | |
double getside() { return side; } | |
void setside(double side) { this -> side = side; } | |
Square(double side) | |
{ | |
this -> side = side; | |
numberOfObjects++; | |
} | |
Square() : Square(1.0) {} | |
static int getNumbers() { return numberOfObjects; } | |
int getN() { return numberOfObjects; } | |
double area() { return side * side; } | |
}; | |
int Square::numberOfObjects; // 初始化 0,不写会 CE | |
int main() | |
{ | |
Square s1; | |
cout << s1.getNumbers() << endl; // 1 | |
Square s2{2.0}; | |
cout << s2.getN() << endl; // 2 | |
cout << Square::getNumbers() << endl; // 2 使用类名 | |
cout << Square::getN() << endl; // Err: 非静态成员引用必须与特定对象相对 | |
return 0; | |
} |
# 析构函数 dtor
- 类名前加
~
,在对象销毁时自动调用。 - 无参数,无返回值,不可重载。
- 自动生成析构函数,可使用
default
和delete
(C++11)
#include <iostream> | |
using namespace std; | |
class Square{ | |
private: | |
static int numberOfObjects; | |
public: | |
Square() { numberOfObjects++; } | |
static int getNumbers() { return numberOfObjects; } | |
~Square() { numberOfObjects--; } | |
}; | |
int Square::numberOfObjects; | |
int main() | |
{ | |
Square s1, s2; | |
cout << Square::getNumbers() << endl; // 2 | |
delete &s2; | |
cout << Square::getNumbers() << endl; // 1 | |
return 0; | |
} |
其它应用:作用域相关,栈区自动销毁时可以进行一些蜜汁操作 qwq
# 友元
授权某些可信的外部函数和类可访问私有成员, 特点是打破了封装性。
使用关键字 friend
在类的内部声明友元。
实例:
#include <iostream> | |
using namespace std; | |
class Square | |
{ | |
private: | |
double side; | |
public: | |
Square(double side = 1.0) | |
{ | |
this -> side = side; | |
} | |
friend class Calculator; // 友元类 | |
friend double getSide(const Square& s); // 友元函数 | |
}; | |
class Calculator | |
{ | |
public: | |
double Square_area(const Square& s) | |
{ | |
return s.side * s.side; | |
} | |
}; | |
double getSide(const Square& s) | |
{ | |
return s.side; | |
} | |
int main() | |
{ | |
Square s1{2.0}; | |
Calculator cal; | |
cout << cal.Square_area(s1) << endl; | |
cout << getSide(s1) << endl; | |
system("pause"); | |
return 0; | |
} |
# 拷贝构造函数
拷贝构造:用一个对象初始化另一个同类对象。
声明拷贝构造函数: Circle(Circle&);
或 Circle(const Circle&);
- 首个参数必须是同类型引用, C++11 可带有默认值的其它参数。
- 仅拷贝构造时会调用拷贝构造函数,区分赋值与拷贝构造,例如
Circle c2 = c1;
是拷贝构造。 - 没有显式声明时,编译器会隐式声明 cp ctor。
实例:
#include <iostream> | |
using namespace std; | |
class C | |
{ | |
private: | |
static int num; | |
public: | |
C() { num++; } | |
C(C&) | |
{ | |
num++; | |
cout << "copyed c" << num << endl; | |
} | |
}; | |
int C::num = 0; | |
int main() | |
{ | |
C c1; | |
C c2 = c1; | |
C c3; | |
c3 = c1; | |
C c4{c1}; | |
return 0; | |
} // 输出 copyed c2, copyed c4 |
# 深拷贝与浅拷贝
深浅拷贝仅对于类中的指针成员而言。
# 浅拷贝 shallow copy
数据域是一个指针,拷贝时只拷贝指针地址,而不拷贝指向内容。你老婆真棒(
- 创建新对象时的隐式 / 默认构造函数。
=
为已有对象赋值的默认运算符。
实例:
#include <iostream> | |
using namespace std; | |
class C | |
{ | |
private: | |
int *p; | |
public: | |
C(int x = 233) | |
{ | |
p = new int; | |
*p = x; | |
} | |
C(C&) = default; | |
void setP(int x) { *p = x; } | |
int getP() { return *p; } | |
}; | |
int main() | |
{ | |
C c1, c2{c1};; | |
cout << c1.getP() << endl; // 233 | |
c2.setP(466); | |
cout << c1.getP() << endl; // 466 | |
return 0; | |
} |
# 深拷贝 deep copy
拷贝指针指向的内容。
- 自行编写拷贝构造函数。
- 重载赋值运算符。
实例:仅需修改上段 cp ctor
...... | |
C(C& c) | |
{ | |
p = new int {*c.p}; | |
} | |
...... | |
int main() | |
{ | |
C c1, c2{c1}; | |
cout << c1.getP() << endl; // 233 | |
c2.setP(466); | |
cout << c1.getP() << endl; // 233 | |
cout << c2.getP() << endl; // 466 | |
return 0; | |
} |