当前位置: 首页 > news >正文

c++类和对象(下)

一、再谈构造函数

我们在之前就已经了解了构造函数,初始化成员变量主要使用的是函数体内赋值。

1、其实,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值表达式。

例如:

2、每个成员变量在初始化成员列表中只能出现一次,,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。

3、引用成员变量、const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则编译会报错。

4、C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

初始化列表总结:1、无论是否显示写初始化列表,每个构造函数都有初始化列表;

2、无论是否在初始化列表显示初始化成员变量,每个成员变量都要走初始化列表初始化。

举例如下:

#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;}

#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++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。

#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就不再支持隐式类型转换

#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_castprintRMB(static_cast<RMB>(1000)); // 正确:显式转换后传参return 0;
}

3、类类型的对象之间也可以隐式转换,需要相应的构造函数支持。

#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生成,仅供参考:

#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 -> Boperator int() const {return num; // 先将 A 转为 int,再借助 B 的构造函数转 B}
};class B {
private:int data;
public:// 接收 A 对象的构造函数:在目标类 B 中定义,实现 A -> BB(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 转类类型 BA 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的友元)。
- 优缺点:提供了突破封装的便利,但增加耦合度、破坏封装,不宜多用。

友元函数举例:

#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;
}

友元类:

#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内使用。

#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、匿名对象

用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的  类型  对象名(实参) 定义出来的叫有名对象。

匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。

举例如下:

#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 命令关闭构造相关的优化。

http://www.dtcms.com/a/473652.html

相关文章:

  • 算法7.0
  • 【异常处理——下】
  • axios请求
  • 109、23种设计模式之迭代器模式(18/23)
  • 餐饮设计公司网站wordpress如何保存
  • 前端页面出现问题ResizeObserver loop completed with undelivered notifications.
  • 有声阅读网站如何建设邵阳学院研究生与学科建设处网站
  • AWS RDS Aurora MySQL高CPU使用率问题诊断与解决实战
  • 【Swift】LeetCode 11. 盛最多水的容器
  • 设计模式之 享元模式 Flyweight
  • 智械觉醒当AI开始思考“我是谁”
  • 商河 网站建设公司网站的具体的建设方案
  • 湖南省网站备案婚纱摄影网站应该如何做优化
  • pytest学习
  • seo网站建设厦门百度广告代理商查询
  • 【全连接神经网络】基本原理
  • Go 异步编程
  • 基于贪心最小化包围盒策略的布阵算法
  • 《Python 异步数据库访问全景解析:从阻塞陷阱到高性能实践》
  • AI 自己造“乐高积木”:生成式 AI 设计可拼装模块化硬件的实战笔记
  • 10.11笔记
  • 冒泡排序的多种实现方式详解
  • 网页设计平面设计温州网站优化页面
  • 特别分享:聊聊Git
  • M|蝙蝠侠:侠影之谜
  • crawl4ai智能爬虫(一):playwright爬虫框架详解
  • 探究Java、C语言、Python、PHP、C#与C++在多线程编程中的核心差异与应用场景
  • 国外网站模板网站建设ui培训班好
  • 瑞安建设公司网站旅游网站系统的设计与实现
  • MongoDB-基本介绍(一)基本概念、特点、适用场景、技术选型