Top

CSDSTDCPP01 DAY03

  1. 返回有效引用
  2. 定义用户类并实例化为对象

1 返回有效引用

1.1 问题

函数返回值通常都具有右值属性,在函数的调用者空间根据函数的返回类型创建一个匿名对象,负责接收该函数的返回值,该匿名对象一般是临时对象。如果函数返回的是一个引用,那么用于接收该返回值的就不再是一个临时对象,而是一个引用该函数所返回引用的目标对象的引用,甚至可以是左值引用。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:返回全局、静态、成员变量的引用

代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
};

int main(int argc, constchar * argv[])
{

    Dummy dummy = {789};
int&rg = dummy.foo ();
std::cout<<"rg = "<< rg << std::endl;
int&rs = dummy.bar ();
std::cout<<"rs = "<< rs << std::endl;
int&rm = dummy.hum ();
std::cout<<"rm = "<< rm << std::endl;

return0;
}

上述代码中,以下代码:

int& foo (void) { returng; }

定义了结构体Dummy的一个成员函数,该函数返回全局变量g的一个引用。

上述代码中,以下代码:

int&rg = dummy.foo ();

定义了一个引用rg,该引用通过返回引用的函数foo使其成为全局变量g的别名,所以,下述语句:

std::cout<<"rg = "<< rg << std::endl;

输出的是全局变量g的值。

上述代码中,以下代码:

int& bar (void) { staticint s = 456; return s; }

定义了结构体Dummy的一个成员函数,该函数返回静态局部整型变量s的一个引用。

上述代码中,以下代码:

int&rs = dummy.bar ();

定义了一个引用rs,该引用通过返回引用的函数bar使其成为静态局部整型变量s的别名,所以,下述语句:

std::cout<<"rs = "<< rs << std::endl;

输出的是静态局部整型变量s的值。

上述代码中,以下代码:

int& hum (void) { returnm; }

定义了结构体Dummy的一个成员函数,该函数返回结构体成员变量m的一个引用。

上述代码中,以下代码:

int&rm = dummy.hum ();

定义了一个引用rm,该引用通过返回引用的函数hum使其成为机构体成员变量m的别名,所以,下述语句:

std::cout<<"rm = "<< rm << std::endl;

输出的是结构体成员变量m的值。

步骤二:返回调用对象自身的引用

代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
Dummy& up (void) { ++m; return *this; }
};

int main(int argc, constchar * argv[])
{

Dummy dummy = {789};
int& rg = dummy.foo ();
std::cout<<"rg = "<< rg <<std::endl;
int& rs = dummy.bar ();
std::cout<<"rs = "<< rs <<std::endl;
int& rm = dummy.hum ();
std::cout<<"rm = "<< rm <<std::endl;

    dummy.up().up().up();
std::cout<<"rm = "<< rm <<std::endl;

return0;
}

上述代码中,以下代码:

Dummy& up (void) { ++m; return *this; }

定义了结构体Dummy的一个成员函数,该函数返回结构体自身*this的一个引用。

上述代码中,以下代码:

    dummy.up().up().up();

相当于写成如下方式:

(dummy.up()).up().up();

因为dummy.up()函数的返回值就是dummy自身,所以(dummy.up()).up()在第一个up函数返回后等效于(dummy).up(),依次类推。

步骤三:返回堆变量的引用

代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
Dummy& up (void) { ++m; return *this; }
};

int& square (int x) {
int* y = newint;
    *y = x * x;
return *y;
}

int main(int argc, constchar * argv[])
{

Dummy dummy = {789};
int& rg = dummy.foo ();
std::cout<<"rg = "<< rg <<std::endl;
int& rs = dummy.bar ();
std::cout<<"rs = "<< rs <<std::endl;
int& rm = dummy.hum ();
std::cout<<"rm = "<< rm <<std::endl;

    dummy.up().up().up();
std::cout<<"rm = "<< rm <<std::endl;

int& y = square(16);
std::cout<< y <<std::endl; // 256
delete&y;

return0;
}

上述代码中,以下代码:

int& square (int x) {
int* y = newint;
    *y = x * x;
return *y;
}

定义了一个返回堆上变量引用的函数,在该函数体中,在堆上申请了一块儿存储空间,并返回该存储空间的引用。

上述代码中,以下代码:

int&y = square(16);

定义了一个引用y,该引用是对上申请的一块儿空间的别名。引用y实质上是一种“野引用”或“悬空引用”。

步骤四:返回引用型参数本身

代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
Dummy& up (void) { ++m; return *this; }
};

int& square (int x) {
int* y = newint;
    *y = x * x;
return *y;
}

intconst& max (intconst& a, intconst& b)
{
return a > b ? a : b;
}

int main(int argc, constchar * argv[])
{

Dummy dummy = {789};
int& rg = dummy.foo ();
std::cout<<"rg = "<< rg <<std::endl;
int& rs = dummy.bar ();
std::cout<<"rs = "<< rs <<std::endl;
int& rm = dummy.hum ();
std::cout<<"rm = "<< rm <<std::endl;

    dummy.up().up().up();
std::cout<<"rm = "<< rm <<std::endl;

int& y = square(16);
std::cout<< y <<std::endl; // 256
delete&y;

int a = 123, b = 456;
std::cout<<&a <<' '<<&b <<std::endl;
intconst& c = max (a, b);
std::cout<<&c <<" : "<< c <<std::endl;

return0;
}

上述代码中,以下代码:

intconst& max (intconst& a, intconst& b)
{
return a > b ? a : b;
}

定义了一个返回常引用的函数,该函数有两个常引用形参,返回的是大的那个常引用形参。

上述代码中,以下代码:

intconst& c = max (a, b);

定义了一个常引用c,它将是整型变量a或b的别名,至于最终是哪一个变量的别名,取决于哪个整型变量的值大。在本例中,由于a被初始化成了123,b被初始化成了456,b大于a,所以常引用c就是变量b的别名。

步骤五:不能返回局部变量的引用

代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
Dummy& up (void) { ++m; return *this; }
};

int& square (int x) {
int* y = newint;
    *y = x * x;
return *y;
}

intconst& max (intconst& a, intconst& b)
{
return a > b ? a : b;
}

int& foo (void)
{
int n = 123;
return n;
}

int main(int argc, constchar * argv[])
{

Dummy dummy = {789};
int& rg = dummy.foo ();
std::cout<<"rg = "<< rg <<std::endl;
int& rs = dummy.bar ();
std::cout<<"rs = "<< rs <<std::endl;
int& rm = dummy.hum ();
std::cout<<"rm = "<< rm <<std::endl;

    dummy.up().up().up();
std::cout<<"rm = "<< rm <<std::endl;

int& y = square(16);
std::cout<< y <<std::endl; // 256
delete&y;

int a = 123, b = 456;
std::cout<<&a <<' '<<&b <<std::endl;
intconst& c = max (a, b);
std::cout<<&c <<" : "<< c <<std::endl;

int&z = foo();
std::cout<<"z = "<< z <<std::endl;

return0;
}

上述代码中,以下代码:

int& foo (void)
{
int n = 123;
return n;
}

是错误的。因为函数foo返回了局部变量n的引用。由于当函数foo运行结束时,变量n所占的存储空间已经被释放,所以返回的引用就没有一块儿合法的存储空间相对应了,这样必然带来不测的后果。所以下面的代码中:

int&z = foo();

引用z所对应的存储空间是一块儿已经被释放的存储空间,这样使用z将是危险的。

1.3 完整代码

本案例的完整代码如下所示:

#include <iostream>

int g = 123;
struct Dummy {
int m;
int& foo (void) { returng; }
int& bar (void) { staticint s = 456; return s; }
int& hum (void) { returnm; }
Dummy& up (void) { ++m; return *this; }
};

int& square (int x) {
int* y = newint;
    *y = x * x;
return *y;
}

intconst& max (intconst& a, intconst& b)
{
return a > b ? a : b;
}

int& foo (void)
{
int n = 123;
return n;
}

int main(int argc, constchar * argv[])
{

Dummy dummy = {789};
int& rg = dummy.foo ();
std::cout<<"rg = "<< rg <<std::endl;
int& rs = dummy.bar ();
std::cout<<"rs = "<< rs <<std::endl;
int& rm = dummy.hum ();
std::cout<<"rm = "<< rm <<std::endl;

    dummy.up().up().up();
std::cout<<"rm = "<< rm <<std::endl;

int& y = square(16);
std::cout<< y <<std::endl; // 256
delete&y;

int a = 123, b = 456;
std::cout<<&a <<' '<<&b <<std::endl;
intconst& c = max (a, b);
std::cout<<&c <<" : "<< c <<std::endl;

int&z = foo();
std::cout<<"z = "<< z <<std::endl;

return0;
}

2 定义用户类并实例化为对象

2.1 问题

定义一个用户类User,该类包含两个私有的数据成员,它们是姓名name和年龄age;包含六个公有的成员函数,它们是带参构造函数User,设置姓名函数setName,获取姓名函数getName,设置年龄函数setAge,获取年龄函数getAge,自我介绍函数who。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:定义用户类

代码如下:

#include <iostream>

class User 
{
private:
std::string m_name;
int m_age;
public:
    User (std::stringconst& name, int age) 
{
m_name = name;
m_age = age;
    }
void setName(std::stringconst& name)
    {
m_name = name;
    }
std::string getName()
    {
returnm_name;
    }
void setAge(const int& age)
    {
m_age = age;
    }
int getAge()
    {
returnm_age;
    }
void who (void);
};

voidUser::who (void) 
{
std::cout<<"我是"<<m_name<<",今年"<< m_age <<"岁。"<< std::endl;
}

上述代码中,以下代码:

class User 

定义了一个类,其中class为关键字,表示开始定义一个类;User为标识符,表示类名。

上述代码中,以下代码:

private:
std::string m_name;
int m_age;

定义了两个私有的数据成员,姓名m_name和年龄m_age。

上述代码中,以下代码:

public:
    User (std::stringconst& name, int age) 
{
m_name = name;
m_age = age;
    }
void setName(std::stringconst& name)
    {
m_name = name;
    }
std::string getName()
    {
returnm_name;
    }
void setAge(const int& age)
    {
m_age = age;
    }
int getAge()
    {
returnm_age;
    }
void who (void);

定义了五个成员函数,它们是带参构造函数User,设置姓名函数setName,获取姓名函数getName,设置年龄函数setAge,获取年龄函数getAge。

声明了一个成员函数,是自我介绍函数who。该函数的定义在类外实现,如以下代码所示:

voidUser::who (void) 
{
std::cout<<"我是"<<m_name<<",今年"<< m_age <<"岁。"<< std::endl;
}

在类外定义函数时,注意使用类名加作用域限定符(User::)说明该函数属于哪一个类。

步骤二:将用户类实例化为对象

代码如下所示:

#include <iostream>

class User
{
private:
std::string m_name;
int m_age;
public:
    User (std::stringconst& name, int age) 
{
m_name = name;
m_age = age;
    }
void setName(std::stringconst& name)
    {
m_name = name;
    }
std::string getName()
    {
returnm_name;
    }
void setAge(constint& age)
    {
m_age = age;
    }
int getAge()
    {
returnm_age;
    }
void who (void);
};

voidUser::who (void) 
{
std::cout<<"我是"<<m_name<<",今年"<< m_age <<"岁。"<< std::endl;
}

intmain(int argc, constchar * argv[])
{


User user("张飞", 25);
    user.who();

    user.setName("关羽");
    user.setAge(28);
    user.who();

return0;
}

上述代码中,以下代码:

User user("张飞", 25);

定义了一个用户类User的对象user。类是用户自定义的一种数据类型,所以可以直接用类名来定义对象。对象名user后面的括号中的内容为类User的构造函数的实参,当为对象user分配完存储空间后将自动调用类的构造函数。

上述代码中,以下代码:

    user.who();

    user.setName("关羽");
    user.setAge(28);
    user.who();

是调用类的成员函数。

2.3 完整代码

本案例的完整代码如下所示:

#include <iostream>

class User
{
private:
std::string m_name;
int m_age;
public:
    User (std::stringconst& name, int age) 
{
m_name = name;
m_age = age;
    }
void setName(std::stringconst& name)
    {
m_name = name;
    }
std::string getName()
    {
returnm_name;
    }
void setAge(const int& age)
    {
m_age = age;
    }
int getAge()
    {
returnm_age;
    }
void who (void);
};

voidUser::who (void) 
{
std::cout<<"我是"<<m_name<<",今年"<< m_age <<"岁。"<< std::endl;
}

intmain(int argc, constchar * argv[])
{


User user("张飞", 25);
    user.who();

    user.setName("关羽");
    user.setAge(28);
    user.who();

return0;
}