一、再谈构造函数
我们在之前就已经了解了构造函数,初始化成员变量主要使用的是函数体内赋值。
1、其实,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始 ,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值表达式。
例如:
2、每个成员变量在初始化成员列表中只能出现一次,,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。
3、引用成员变量、const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则编译会报错。
4、C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。
初始化列表总结:1、无论是否显示写初始化列表,每个构造函数都有初始化列表;
2、无论是否在初始化列表显示初始化成员变量,每个成员变量都要走初始化列表初始化。

举例如下:
cpp
#include <iostream>
using namespace std;
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)//初始化列表
, _day(day)
{
//_year = year;
} int GetRet() const {
return _ret;
}
private:
//声明
int _year=2000;//缺省值
int _month=12;
int _day;
int _ret=20;
};
int main()
{
int xx;
Date d1( 2025, 12, 22);
cout << d1.GetRet() << endl;
return 0;
}
cpp
#include<iostream>
using namespace std;
class Time
{
public:
Time(int hour)
:_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
Date()
:_month(2)
{
cout << "Date()" << endl;
}
void Print() const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// 注意这⾥不是初始化,这⾥给的是缺省值,这个缺省值是给初始化列表的
// 如果初始化列表没有显⽰初始化,默认就会⽤这个缺省值初始化
int _year = 1;
int _month = 1;
int _day;
Time _t = 1;
const int _n = 1;
int* _ptr = (int*)malloc(12);
};
int main()
{
Date d1;
d1.Print();
return 0;
}
二、类型转换
在c语言中,我们学过的类型转换:
(1)整型之间(2)整型和浮点数之间(3)整型和指针之间(4)指针和指针之间
在c++中支持:内置类型-->类类型 类类型-->类类型
1、c++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
cpp
#include <iostream>
using namespace std;
// 人民币金额类
class RMB {
private:
int yuan; // 存储金额(单位:元)
public:
// 单参数构造函数:接收int类型(内置类型),用于隐式转换
RMB(int y) : yuan(y) {
cout << "触发隐式转换:int(" << y << ") -> RMB 对象" << endl;
}
// 成员函数:显示金额
void showMoney() {
cout << "当前金额:" << yuan << " 元" << endl;
}
};
int main() {
// 关键代码:直接用int值给RMB对象赋值,触发隐式转换
RMB myMoney = 500; // 等价于 RMB myMoney(500),但这里是隐式转换
myMoney.showMoney();
// 另一种隐式转换场景:函数参数传递
void printRMB(RMB m); // 声明函数
printRMB(1000); // 直接传int值,隐式转为RMB对象
return 0;
}
// 定义函数:参数为RMB类型
void printRMB(RMB m) {
cout << "函数接收的金额:";
m.showMoney();
}
2、构造函数前面加上explicit就不再支持隐式类型转换
cpp
#include <iostream>
using namespace std;
class RMB {
private:
int yuan;
public:
// 关键:构造函数前加 explicit,禁止隐式转换
explicit RMB(int y) : yuan(y) {
cout << "显式创建 RMB 对象,金额:" << y << " 元" << endl;
}
void showMoney() {
cout << "当前金额:" << yuan << " 元" << endl;
}
};
// 函数:接收 RMB 类型参数
void printRMB(RMB m) {
m.showMoney();
}
int main() {
// 1. 尝试隐式转换:编译报错!因为构造函数加了 explicit
// RMB myMoney = 500; // 错误:无法从 int 隐式转换为 RMB
// 2. 尝试函数参数隐式转换:同样编译报错
// printRMB(1000); // 错误:无法将参数 1 从 int 转换为 RMB
// 3. 仅支持显式转换:通过直接调用构造函数实现
RMB myMoney(500); // 正确:显式创建对象
myMoney.showMoney();
// 4. 显式转换的另一种方式:使用 static_cast
printRMB(static_cast<RMB>(1000)); // 正确:显式转换后传参
return 0;
}
3、类类型的对象之间也可以隐式转换,需要相应的构造函数支持。
cpp
#include <iostream>
using namespace std;
// 源类:手机(存储电量)
class Phone {
public:
int power;
Phone(int p) : power(p) {} // 源类构造
};
// 目标类:充电宝(支持从手机转换,接收Phone对象的构造函数是关键)
class PowerBank {
public:
int store;
// 接收Phone的构造函数:支持Phone→PowerBank隐式转换
PowerBank(const Phone& ph) : store(ph.power) {
cout << "隐式转换:手机电量→充电宝存储" << endl;
}
void show() { cout << "充电宝存储:" << store << "%" << endl; }
};
int main() {
Phone myPhone(60); // 创建手机对象(60%电量)
PowerBank pb = myPhone; // 隐式转换:手机→充电宝
pb.show(); // 输出结果
return 0;
}
c++中类型转换 ,以下代码由AI生成,仅供参考:
cpp
#include <iostream>
using namespace std;
// 1. 演示:内置类型(int)转换为类类型(MyInt)
class MyInt {
private:
int value;
public:
// 单参数构造函数:实现 int -> MyInt(不加 explicit 允许隐式转换)
MyInt(int v) : value(v) {
cout << "内置类型 int 转换为 MyInt,值为:" << value << endl;
}
void showValue() {
cout << "MyInt 的值:" << value << endl;
}
};
// 2. 演示:类类型(A)转换为另一种类类型(B)
class A {
private:
int num;
public:
A(int n) : num(n) {}
// 类型转换函数:在源类 A 中定义,实现 A -> B
operator int() const {
return num; // 先将 A 转为 int,再借助 B 的构造函数转 B
}
};
class B {
private:
int data;
public:
// 接收 A 对象的构造函数:在目标类 B 中定义,实现 A -> B
B(const A& a) : data(static_cast<int>(a)) {
cout << "类 A 转换为类 B,B 的值为:" << data << endl;
}
};
int main() {
// 测试1:内置类型 int 转类类型 MyInt(隐式转换)
MyInt obj1 = 10; // 等价于 MyInt obj1(10)
obj1.showValue();
// 测试2:类类型 A 转类类型 B
A a(20);
B b = a; // 调用 B 的构造函数,接收 A 对象完成转换
return 0;
}
三、static成员
(1)用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化 。
(2)静态成员变量为所有类对象共享,不属于某个具体的对象,不存在对象中,存放在静态区。
(3)用static修饰的成员函数,叫做静态成员函数,静态成员函数没有this指针。
(4)非静态成员函数,可以访问任意的静态成员变量和静态成员函数。
(5)静态成员函数中可以访问其他的静态成员,但是不能访问非静态的,因为没有this指针。
(6)突破类域可以访问静态成员,可以通过 类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。
(7)静态成员也是类的成员,受public,protected,private访问限定符修饰。
(8)静态成员变量不能在声明的位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。
4、友元
- 分类:分为友元函数和友元类,声明时在函数或类前加 friend ,且声明放在类内部。
------------------- 友元函数:
-(1) 可访问类的私有和保护成员,但不是类的成员函数。
-
(2)可在类内任意位置声明,不受访问限定符限制。
-
(3)一个函数可作为多个类的友元函数。
-
---------------------友元类:
-
(1)其所有成员函数都可访问另一个类的私有和保护成员。
-(2) 关系是单向的(如A是B的友元,B不一定是A的友元)且不可传递(A是B的友元、B是C的友元,A不是C的友元)。
- 优缺点:提供了突破封装的便利,但增加耦合度、破坏封装,不宜多用。
友元函数举例:
cpp
#include <iostream>
using namespace std;
class Student {
private:
string name;
int score;
public:
Student(string n, int s) : name(n), score(s) {}
// 声明友元函数
friend void showStudentInfo(Student& stu);
};
// 友元函数:可访问Student的私有成员
void showStudentInfo(Student& stu) {
cout << "姓名:" << stu.name << ",分数:" << stu.score << endl;
}
int main() {
Student s("小明", 95);
showStudentInfo(s);
return 0;
}
友元类:
cpp
#include <iostream>
using namespace std;
class Car {
private:
string brand;
int price;
public:
Car(string b, int p) : brand(b), price(p) {}
// 声明友元类
friend class CarDealer;
};
class CarDealer {
public:
// 可访问Car的私有成员
void getCarInfo(Car& car) {
cout << "汽车品牌:" << car.brand << ",价格:" << car.price << "万" << endl;
}
};
int main() {
Car c("宝马", 35);
CarDealer dealer;
dealer.getCarInfo(c);
return 0;
}
5、内部类
内部类是定义在另一个类内部的独立类,受外部类的类域和访问限定符限制,外部类对象不包含内部类。内部类默认是外部类的友元类,能访问外部类成员。它是一种封装方式,若类A与类B紧密关联且主要为类B服务,可将类A设为类B的内部类;若把类A放在 private 或 protected 位置,类A就成为类B的专属内部类,只能在类B内使用。
cpp
#include <iostream>
using namespace std;
class Car { // 外部类
private:
string brand = "Tesla";
int price = 30;
// 内部类:专门为Car服务,封装汽车的电子系统逻辑
class ElectronicSystem {
public:
void checkBattery() {
// 内部类可访问外部类私有成员
cout << brand << " 电池状态正常,车辆价值 " << price << " 万" << endl;
}
};
public:
void startCar() {
ElectronicSystem es; // 外部类中创建内部类对象
es.checkBattery();
cout << "汽车启动成功" << endl;
}
};
int main() {
Car myCar;
myCar.startCar();
// 错误示例:无法在类外直接访问内部类 ElectronicSystem(因它是 Car 的私有内部类)
// Car::ElectronicSystem es;
return 0;
}
6、匿名对象
用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。
匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。
举例如下:
cpp
#include <iostream>
using namespace std;
class Person {
private:
string name;
int age;
public:
Person(string n, int a) : name(n), age(a) {
cout << "构造函数调用" << endl;
}
~Person() {
cout << "析构函数调用" << endl;
}
void showInfo() {
cout << "姓名:" << name << ",年龄:" << age << endl;
}
};
// 函数:接收 Person 对象作为参数
void printPerson(Person p) {
p.showInfo();
}
int main() {
// 示例1:匿名对象作为函数参数(临时传递,调用后立即析构)
printPerson(Person("张三", 20));
// 示例2:匿名对象直接调用成员函数(调用后立即析构)
Person("李四", 25).showInfo();
return 0;
}
7、对象拷贝时的编译器优化
- 优化目的:现代编译器为提升程序效率,在不影响正确性的前提下,会减少传参、返回值过程中可省略的对象拷贝。
- 优化规则:C++标准未严格规定优化方式,各编译器自行处理。主流新编译器会对连续表达式中的连续拷贝进行合并优化,部分"激进"编译器还支持跨行跨表达式的合并优化。
- 优化控制(Linux环境):可将代码保存为 test.cpp ,编译时通过 g++ test.cpp -fno-elide-constructors 命令关闭构造相关的优化。