这篇讨论的是如何在函数返回两个值
cherno推荐的方法是创建一个结构体并返回它
代码预备#
为了演示,本篇使用了string,为了顺便探讨性能(视频中没提到),我写了一个string.h 和string.cpp打印相关信息
//String.h
#pragma once // 防止头文件被重复包含
#include <iostream>
class String
{
private:
char* m_Buffer;
unsigned int m_Size;
public:
// 默认构造函数
String() : m_Buffer(nullptr), m_Size(0) {}
// 构造函数
String(const char* string);
// 拷贝构造函数(深拷贝)
//拷贝构造函数 (String a = b;):当你在创建一个新的对象,并用已有的对象初始化它时调用。
String(const String& other);
// 析构函数
~String();
// 运算符重载
char& operator[](unsigned int index);
// 赋值运算符重载 (a = b;):当两个对象都已经存在(已经构造完毕),你只是想把其中一个的值覆盖给另一个时调用。
String& operator=(const String& other);
// 友元函数:重载 << 运算符
friend std::ostream& operator<<(std::ostream& stream, const String& string);
// 测试函数
unsigned int& mytest() { return m_Size; } // 简单的内联函数可以直接写在类内
};
#include "String.h"
#include <cstring> // 必须包含 cstring 才能使用 strlen 和 memcpy
// 构造函数
String::String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, string, m_Size);
m_Buffer[m_Size] = '\0';
}
// 拷贝构造函数
String::String(const String& other)
: m_Size(other.m_Size)
{
std::cout << "Copied String!" << std::endl;
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
}
//赋值运算符
String& String::operator=(const String& other)
{
std::cout << "Assignment Operator Called!" << other << std::endl;
// 1. 自赋值检查 (防止 s1 = s1 的骚操作)
if (this == &other)
return *this;
// 2. 释放当前对象旧的内存,防止内存泄漏
delete[] m_Buffer;
// 3. 申请新空间并拷贝内容
m_Size = other.m_Size;
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
// 4. 返回对象自身,支持链式赋值 (a = b = c)
return *this;
}
// 析构函数
String::~String()
{
delete[] m_Buffer;
}
// 下标运算符重载
char& String::operator[](unsigned int index)
{
return m_Buffer[index];
}
// 友元函数定义(注意:定义时不需要加 String::,也不需要加 friend 关键字)
std::ostream& operator<<(std::ostream& stream, const String& string)
{
stream << string.m_Buffer;
return stream;
}
方法1:使用引用#
#include <iostream>
#include "String.h"
void ParseShader(String& vertexSource, String& fragmentSource)
{
//假设vs,fs最终计算值是abc、def
String vs = "abc";
String fs = "def";
//这两行代码执行的是 字符串赋值(内部会拷贝)
vertexSource = vs;
fragmentSource = fs;
}
int main()
{
String vs, fs;
ParseShader(vs, fs);
std::cout << vs << std ::endl;
std::cout << fs << std::endl;
std::cin.get();
}
/*
Assignment Operator Called!abc
Assignment Operator Called!def
abc
def
*/
方法2:使用指针#
#include <iostream>
#include "String.h"
void ParseShader(String* vertexSource, String* fragmentSource)
{
//假设vs,fs最终计算值是abc、def
String vs = "abc";
String fs = "def";
//这两行代码执行的是 字符串赋值(内部会拷贝)
if (vertexSource) {
*vertexSource = vs;
}
if (fragmentSource) {
*fragmentSource = fs;
}
}
int main()
{
String vs, fs;
ParseShader(&vs, &fs);
//这种方式允许空指针
//ParseShader(nullptr, &fs);
std::cout << vs << std::endl;
std::cout << fs << std::endl;
std::cin.get();
}
/*
Assignment Operator Called!abc
Assignment Operator Called!def
abc
def
*/
(同类型)方法3:返回(数组)指针#
#include <iostream>
#include "String.h"
String* ParseShader()
{
//假设vs,fs最终计算值是abc、def
//vs,fs先在栈上创建(但String成员m_Buffer是指向堆)
String vs = "abc";
String fs = "def";
//这种语法在c++20才能编译通过
return new String[]{ vs,fs };
}
int main()
{
//这里不知道数组有多大
String* result =ParseShader();
std::cout << result[0] << std::endl;
std::cout << result[1] << std::endl;
std::cin.get();
}
/*
Assignment Operator Called!abc
Assignment Operator Called!def
abc
def
*/
分析: