c++类和对象(下)

一、再谈构造函数

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

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 命令关闭构造相关的优化。
相关推荐
应用市场4 小时前
Qt插件机制实现动态组件加载详解
开发语言·qt
小秋学嵌入式-不读研版4 小时前
C65-枚举类型
c语言·开发语言·笔记
艾莉丝努力练剑4 小时前
【Linux指令 (二)】不止于入门:探索Linux系统核心与指令的深层逻辑,理解Linux系统理论核心概念与基础指令
linux·服务器·数据结构·c++·centos
深栈5 小时前
机器学习:支持向量机
算法·机器学习·支持向量机
Mr_WangAndy5 小时前
C++设计模式_结构型模式_外观模式Facade
c++·设计模式·外观模式
FreeBuf_5 小时前
Happy DOM曝CVSS 9.4严重RCE漏洞,PoC已公开(CVE-2025-61927)
java·c语言·c++·python·php
刘海东刘海东5 小时前
结构型智能科技理论研究(草稿)
科技·算法
BlackQid5 小时前
深入理解指针Part4——字符、数组与函数指针变量
c++·后端
C嘎嘎嵌入式开发5 小时前
(10)100天python从入门到拿捏《Python中的数据结构与自定义数据结构》
数据结构·python·算法