类的私有成员
定义类成员时使用关键字private,私有类成员只能被类的成员函数访问。
必要时,public函数成员可以提供对包括private成员在内的所有类成员的间接访问。
如果没有另外指定,默认访问特性是private。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
void showmsg()
{
std::cout << name << "'age is " << age << std::endl;
}
public:
void show()
{
std::cout << "show() is called" << std::endl;
showmsg();
}
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
};
int main()
{
CPerson person1;
//person1.showmsg(); //私有成员不能被访问
person1.show();
}
访问私有类成员
public函数成员可以提供对包括private成员在内的所有类成员的间接访问。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
void showmsg()
{
std::cout << name << "'age is " << age << std::endl;
}
public:
inline int getAge()
{
return age;
}
void show()
{
std::cout << "show() is called" << std::endl;
showmsg();
}
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
};
int main()
{
CPerson person1;
//person1.showmsg(); //私有成员不能被访问
person1.show();
//std::cout << person1.age << std::endl; //私有成员不能被访问
std::cout << person1.getAge() << std::endl;
}
类的友元函数
友元函数:不是类的成员的函数能够访问类的所有成员。
使用关键字friend来定义,可以在定义中添加友元函数的原型,也可以添加整个函数定义。
在类定义内定义的友元函数默认也是内联函数。
友元函数声明放在类的内部,友元函数的定义放在类外部。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
friend void show(CPerson cPerson); //类内友元函数声明
public:
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
};
//类外友元函数定义
void show(CPerson cPerson)
{
std::cout << cPerson.name << "'age is " << cPerson.age << std::endl;
}
int main()
{
CPerson person1;
show(person1);
}
将友元函数定义放在类的内部,这样影响可读性,虽然仍然是全局作用域。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
friend void show(CPerson cPerson)//友元函数声明和定义
{
std::cout << cPerson.name << "'age is " << cPerson.age << std::endl;
}
public:
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
};
int main()
{
CPerson person1;
show(person1);
}
默认复制构造函数
编译器生成默认的复制构造函数。
复制构造函数通过同类的现有对象进行初始化来创建类对象。
复制构造函数的默认版本通过逐个成员复制现有对象来创建新对象。
如果拥有指针成员的类,默认复制构造函数将不能正常工作。这种情况下,必须创建自己的复制构造函数。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
friend void show(CPerson cPerson)//友元函数声明和定义
{
std::cout << cPerson.name << "'age is " << cPerson.age << std::endl;
}
public:
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
};
int main()
{
CPerson person1(2,"copy");
CPerson person2(person1); //调用默认复制构造函数
show(person2);
}
this指针
任何成员函数执行时,都自动包含一个名为this的隐藏指针,它指向调用该函数时使用的对象。
如果需要,也可以在成员函数中显式地使用this指针。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
friend void show(CPerson cPerson)//友元函数声明和定义
{
std::cout << cPerson.name << "'age is " << cPerson.age << std::endl;
}
public:
CPerson(int age = 4, std::string name = "tiger") :age{age},name{name}
{
std::cout << "Constructor called "<< std::endl;
}
void setAge(int age)
{
this->age = age;
}
};
int main()
{
CPerson person1(2,"copy");
CPerson person2(person1);
show(person2);
person2.setAge(40);
show(person2);
}
类的const对象
如果将某个类对象声明为const,则编译器将不允许该对象调用任何可能修改它的成员函数。
声明为const的对象,其this指针也是const,因此编译器不允许调用没有将传递给它的this指针指定为const的成员函数。
类的const成员函数
为了使成员函数中的this指针称为const,必须在类定义内将该函数声明为const。
只能对类成员函数这么做,对普通全局函数不能这么做。
function_type function_name(parameter_list) const //必须在类内部的函数
{
}
类外部的成员函数定义
当const成员函数的定义出现在类外部时,函数头必须添加关键字const。
class class_name
{
function_type function_name(parameter_list) const; //类内部
}
function_type function_name(parameter_list) const
{
}
类对象的数组
可创建类对象的数组。
class class_name
{
}
class_name variable[count]; //类对象的数组
类的静态成员
类的静态数据成员
将类的某个数据成员声明为static时,只能定义一次该静态数据成员,而且要被同类的所有对象共享。
每个静态数据成员只有一个实例存在,与定义了多少类对象无关。
在类定义外部初始化静态数据成员的初始化,初始化语句中没有使用static关键字,需要使用类名和作用域解析运算符来限定成员名。
class class_name
{
static variable_type static_variable; //类内定义
}
variable_type class_name::static_variable{}; //类外初始化
类的静态函数成员
通过将某个函数成员声明为static可以使该函数独立于本类的任何具体对象。
它们没有this指针。
static函数的优点:即使本类的任何对象都不存在,它们也能存在并被调用。此时,静态函数成员只能使用静态数据成员(这时就有静态数据成员存在)。
class class_name
{
static function_type static_function(parameter_list)
{
}; //类内定义
}
class_name::static_function(parameter_list); //类外通过类名调用
class_name class_name_example;
class_name_example.static_function(parameter_list); //类外实例调用
类对象的指针和引用
类对象可能涉及相当多的数据,因此对对象使用按值传递机制非常耗时和低效,因为需要赋值每一个实参对象。
使用引用形参可以避免这个系统开销,而且引用形参对于一些类的操作是必不可少的。
类对象的指针
能以声明其他指针的相同方式,声明指向类的指针。
class class_name
{
}
class_name* ptr{};//类的指针
class_name class_name_example;
ptr = &class_name_example;
类对象的引用
声明和使用类对象的引用与声明,和使用基本类型变量的引用之间,实质上没任何区别。
引用是已存在变量的别名,而指针是存储变量地址的变量。
①C++中的引用本质上是 一种被限制的指针
②由于引用是被限制的指针,所以引用是占据内存的。
③在使用高级语言的层面上,是没有提供访问引用的方法的。并且引用创建时必需初始化,创建后还不能修改。
实现复制构造函数
复制构造函数是用同类的现有对象进行初始化,从而创建新对象的构造函数,因此需要接受同类的对象作为实参。
编译器为了处理复制构造函数的这条调用语句,需要调用复制构造函数来创建实参的副本。但是,由于按值传递,第二次调用同样需要创建实参的副本,因此还得调用复制构造函数,就这样持续不休。
解决方法是使用const引用形参。
如果函数的形参是引用,则调用该函数时不需要复制实参。函数直接访问被调用函数中的实参变量。const限定符用来确保该函数不能修改实参。
#include <iostream>
#include <iomanip>
#include <string>
class CPerson
{
//private: 可以省略
std::string name;
int age;
public:
CPerson(int age = 4, std::string name = "tiger") :age{ age }, name{ name }
{
std::cout << "Constructor called " << std::endl;
}
CPerson(const CPerson& cPerson) //复制构造函数
{
this->age = cPerson.age;
this->name = cPerson.name;
std::cout << "Copy Constructor called " << std::endl;
}
};
int main()
{
CPerson person1(2, "copy");
CPerson person2(person1);//复制构造函数
}