admin管理员组

文章数量:1438860

C++: 类和对象(下)

1.0 类型转换

  • C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数、
  • 构造函数前⾯加explicit就不再⽀持隐式类型转换
代码语言:javascript代码运行次数:0运行复制
class QQ {
public:
    //加上explicit就不支持隐私类型转换
    //explicit QQ(int q1) 
    QQ(int q1)
    {
        qq1 = q1;
        cout << "QQ constructed with int: " << q1 << endl;
    }
    //explicit QQ(int q1, int q2)
    QQ(int q1, int q2)
        :qq1(q1)
        ,qq2(q2)
    {}
    void show() const {
        cout << "Value: " << qq1 << qq2 << endl;
    }

private:
    int qq1;
    int qq2;
};

int main() {
    //构造⼀个QQ的临时对象,再⽤这个临时对象拷⻉构造a3
    // 编译器遇到连续构造+拷⻉构造->优化为直接构造
    QQ  a = 1;
    a.show();

    const QQ& a2 = 1;

    //C++11之后才⽀持多参数转化
    QQ a3 = { 3,3 };

    return 0;
}

2.0 static成员

  • ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化。
  • 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。
  • ⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
  • 静态成员函数中可以访问其他的静态成员,但是不能访问⾮静态的,因为没有this指针。
  • ⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
  • 突破类域就可以访问静态成员,可以通过类名::静态成员或者对象.静态成员来访问静态成员变量 和静态成员函数。
  • 静态成员也是类的成员,受public、protected、private访问限定符的限制。
  • 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员 变量不属于某个对象,不⾛构造函数初始化列表。
代码语言:javascript代码运行次数:0运行复制
class MyClass {
public:
 static void fun() {
        // 访问静态成员变量
        cout << val<< std::endl;
    }
	static int val;
};

// 类外初始化
int MyClass::val= 10;


//通过类名访问
MyClass::val = 10;
MyClass::fun();

//通过对象名(不推荐)
MyClass obj;
obj.val= 20;
obj.fun();

3.0 友元

友元是 C++ 中的一种特殊机制,它允许外部的函数或类访问类的私有成员和保护成员。通常情况下,类的私有成员不能被外部直接访问,但通过友元声明,类可以赋予特定的函数或类访问这些成员的权限。

3.1.0 友元函数

代码语言:javascript代码运行次数:0运行复制
class QQ {
private:
	int _val;

public:
	QQ(int val) 
		: _val(val)
	{}

	// 声明外部函数为友元
	friend void display(const QQ& obj);
};

// 友元函数
void display(const QQ& obj) {
	cout << "Private _val: " << obj._val << endl;
}

display函数作为QQ的有元函数被声明,因此可以访问QQ里的私有成员。

外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。

3.2.0 友元类

代码语言:javascript代码运行次数:0运行复制
class QQ {
private:
	int _val;

public:
	QQ(int val) 
		: _val(val)
	{}

	// 声明QQFriend类为友元
	friend class QQFriend;
};
class QQFriend {
public:
	void display(const QQ& obj)
	{
		// 可以访问 MyClass 的私有成员
		cout << "Private _val: " << obj._val << endl;
	}
};

QQFriend 被声明为QQ的友元类,QQFriend类可以访问QQ的private。

3.3.0 注意:

  • 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。
  • ⼀个函数可以是多个类的友元函数。
  • 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
  • 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。
  • 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。
  • 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。

4.0 内部类

⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。

内部类默认是外部类的友元类。

内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考 虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其 他地⽅都⽤不了。

代码语言:javascript代码运行次数:0运行复制
class OuterClass {
private:
	int _OuterVal;

public:
	OuterClass(int val) : _OuterVal(val) {}

	// 内部类定义
	//默认InnerClass为OuterClass的友元类
	class InnerClass {
	private:
		int _innerVal;

	public:
		InnerClass(int val) : _innerVal(val) {}

		void display(const OuterClass& O) {
			cout << "Inner class variable: " << _innerVal << endl;
			cout << "Outer class variable: " << O._OuterVal << endl;
		}
	};

	void displayOuter() {
		cout << "Outer class variable: " << _OuterVal << endl;
	}
};

5.0 匿名对象

匿名对象是指那些没有显式名称的对象,通常在创建时被直接初始化并使用。

匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象。

5.1.0 临时对象

代码语言:javascript代码运行次数:0运行复制
class QQ {
public:
	QQ() 
    {
        cout << "QQ()\n"; 
    }
	~QQ() 
    { 
        cout << "~QQ()\n"; 
    }
};

int main() 
{
	// 创建匿名对象并直接调用它的构造函数
	QQ();
	// 程序结束时会调用匿名对象的析构函数
	return 0;
}

匿名对象 QQ() 被创建,但没有被保存为任何变量。它在创建后立即被销毁。

5.2.0 临时对象作为函数参数

代码语言:javascript代码运行次数:0运行复制
class QQ {
public:
	QQ(int value) 
    { 
        cout << "QQ(int value) " << value << endl; 
    }
	~QQ() 
    {
        cout << "~QQ()\n"; 
    }
};

void func(QQ obj) 
{
	cout << "func(QQ obj)\n";
}

int main() 
{
	func(QQ(10));  // 创建一个匿名对象并传递给函数
	return 0;
}

QQ(10)创建了一个匿名对象,并将其作为参数传递给 func 函数。函数执行完毕后,匿名对象的析构函数被调用。

5.3.0 通过返回值创建匿名对象

代码语言:javascript代码运行次数:0运行复制
class QQ {
public:
	QQ() 
	{ 
		cout << "QQ()\n"; 
	}

	~QQ()
	{
		cout << "~QQ()\n";
	}
};

QQ func() {
	return QQ();  // 返回一个匿名对象
}

int main() {
	QQ obj = func();  // 接收匿名对象
	return 0;
}

func函数返回了一个匿名对象 QQ(),并在 main 函数中接收。匿名对象在返回后立即创建并销毁,构造和析构函数被调用。

6.0 拷贝构造时编译器的优化

如何优化C++标准并没有严格规定,各个编译器会根据情况⾃⾏处理。当前主流的相对新⼀点的编 译器对于连续⼀个表达式步骤中的连续拷⻉会进⾏合并优化,有些更新更"激进"的编译器还会进⾏ 跨⾏跨表达式的合并优化。

代码语言:javascript代码运行次数:0运行复制
class QQ
{
public:
	QQ(int a = 0)
		:_a1(a)
	{
		cout << "QQ(int a = 0)——构造" << endl;
	}
	QQ(const QQ& aa)
		:_a1(aa._a1)
	{
		cout << "QQ(const QQ& aa)——拷贝构造" << endl;
	}
	QQ& operator=(const QQ& aa)
	{
		cout << "QQ& operator=(const QQ& aa)——赋值构造" << endl;
		if (this != &aa)
		{
			_a1 = aa._a1;
		}
		return *this;
	}
	~QQ()
	{
		cout << "~QQ()——析构" << endl;
	}
private:
	int _a1 = 1;
};
void f1(QQ aa)
{}
QQ f2()
{
	QQ qq;
	return qq;
}
  • 隐式类型,直接构造 + 拷⻉构造-> 优化为直接构造
  • 直接构造 + 拷⻉构造-> 优化为直接构造
  • 直接构造+拷贝构造+拷贝构造 -> 优化为直接构
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-21,如有侵权请联系 cloudcommunity@tencent 删除函数优化c++变量对象

本文标签: C 类和对象(下)