C++笔记|类与对象

一、类

1.定义

对具有相似属性和行为的一组对象的统一描述

2.内容

数据成员,成员函数

3.定义形式

(1)用class

class 类名(首字母大写){
	private:
		私有的数据成员或成员函数
                在类之外不能被访问,只有类中的成员函数可以访问private的数据成员和成员函数
                定义类时,若未指明,默认为private
	protected:
		保护的数据成员或成员函数
                只有类的成员函数及其子类(派生类)可以访问protected的成员
	public: 
		公有的数据成员或成员函数
                与外界的接口。外界只有通过这个接口才可以访问private的成员
}; 

此处:各成员函数实现的代码 

(2)用struct

把上面代码的class换成struct即可,唯一区别是:未指明成员的访问属性时,默认为public

4.成员函数的定义

//1.在类中直接定义成员函数
//函数规模较小 ,一般为内联函数 
class Book{
	private:
		char name[20];
		int number;
	public:
		void regist(char *newName, int newNumber) {//成员函数regist()的定义 
			strcpy(name, newName);//给数据成员name赋值
			number = newNumber;//给成员number赋值 
		}
		void show() {
			cout << "名称:"<<name<<endl;
			cout << "号码:"<<number<<endl;
		} 
}; 

//2.在类中写声明,定义放在类后
//函数规模较大
//函数名前加上 类名:: 
class Book{
	private:
		char name[20];
		int number;
	public:
		//成员函数regist()的声明 
		void regist(char *newName, int newNumber);
		//成员函数show()的声明 
		void show();
}; 
    //成员函数regist()的定义 
	void Book::regist(char *newName, int newNumber) {
			strcpy(name, newName);//给数据成员name赋值
			number = newNumber;//给成员number赋值 
	}
	//成员函数show()的定义 
	void Book::show() {
			cout << "名称:"<<name<<endl;
			cout << "号码:"<<number<<endl;
	} 

5.编译器自动生成成员函数

若以下成员函数,用户没有为类实现,则编译器自动实现;若用户定义了,则编译器不提供默认实现

  • 默认构造函数-空函数,什么也不做
  • 析构函数-空函数,什么也不做(涉及指针的话就不对)
  • 拷贝构造函数-按bit位复制对象所占内存的内容
  • 移动构造函数-与默认拷贝构造函数一样
  • 赋值运算符重载 -与默认拷贝构造函数一样

在默认函数定义或声明加上default,可显式生成默认函数

class T {
	int data;
	public:
		T() = default;
		T(int i) : data(i) {}
}; 

//T::T()=default; 

6.类文件的管理

类的说明放在头文件(Book.h)中,看作类的外部借口;成员函数的定义放在源文件(Book.cpp)中,看作类的内部实现。

#include<Book.h>
void Book::regist(char *a, int b){}

二、对象

1.定义

对象是类的实例

2.定义格式

类名 对象名Book book1, book2;book1是Book类型的变量,是Book类的对象

3.内容

每个对象有各自独立的存储单元;每个对象各自具有该类定义的一套数据成员(静态数据成员除外);成员函数是所有对象共有的,每个对象的函数成员都通过指针指向同一个代码空间

4.访问对象的成员

两种方法

void main {

//法1,对象.成员
	Book book1, book2;
	
	//调用成员函数regist,给book1的成员赋值
	book1.regist("abc", 1001); 
	//调用成员函数regist,给book1的成员赋值
	book2.regist("def", 1002);
        
        //这里,成员函数如何知道某次调用的对象?其实regist除了接收两个实参外,还接收了一个对象book1的地址,被隐含的形参this所获取,即this = &book1,所有数据成员的访问都会加上this->,即
        strcpy(this->name, newName);
	this->number = newNumber;
	
	//调用成员函数show,显示book1对象的数据成员的值
	book1.show(); 
        
//法2
    Book book3, *p = &book3;
    p->show();
}

调用公有成员函数->向对象发送消息->对对象私有数据的访问

5.this指针

当参数与成员名称相同时,用this指针区别,this->的是成员

	void Book::regist(char *name, int number) {
			strcpy(this->name, name);//给数据成员name赋值
			this->number = number;//给成员number赋值 
	}

6.作用域与生存期

(1)局部自动对象(包括函数的对象参数)

  • 作用域是定义它的代码块或函数体
  • 生存期从代码块的开始执行到代码块结束
  • 每次执行代码块时重新构造对象

(2)静态对象(局部静态对象、全局对象)

  • 作用域:定义它的函数体或程序文件
  • 生存期:程序的某一次的整个运行期
  • 构造静态对象的次序是按它们在程序中出现的先后次序,并在整个程序运行开始时(主函数运行前)只构造一次

7.初值

  • 静态变量/对象:创建时自动赋初值0
  • 自动变量/对象:创建时初值不确定
class Person{
	private:
		char name[20];
		int age;
	public:
		void show() {
			cout<<"Name:"<<name<<"|age:"<<age<<endl;
		}
}person1;//定义静态对象 


//静态对象:在所处模块初次运行时进行初始化工作,且只初始化一次 
person1.show();//输出: |0 

//自动对象:只有当定义它的函数被调用时才存在的对象 
person person2;
person2.show(); //输出:烫烫烫|-8565634 

8.初始化

//法1:只包含公有数据成员的类的对象可以这样初始化
//不建议用 
class Date {
	public:
		int year, month, day;
};
today = {2008, 2, 10};

struct Date {
		int year, month, day;
};
today = {2008, 2, 10};

//法2:利用构造函数

9.构造函数

(1)定义:构造函数是与类同名的成员函数,当创建对象时,构造函数被自动调用,可以用来对新对象进行初始化

(2)定义格式:类名(形参说明){函数体}

(3)注意

  • 不能为构造函数指定返回值类型(包括void)
  • 构造函数的定义可与其它函数成员一样,放在类说明的内部或外部均可
  • 构造函数可有参,也可无参
  • 每个类必须有一个构造函数
  • 若类中未显式构造,则默认为一个函数体为空的无参函数,不做任何初始化操作;若显式构造了,则不再提供默认构造函数
  • 在用默认构造函数创建对象时,若创建的是全局对象或静态对象,则对象的默认值为0,否则初始值不确定
  • 构造函数和成员函数可以重载
#include<string.h>
#include<iostream.h>

class Person{
	private:
		char name[20];
		int age;
		int salary;
		char tel[8];
	public:
		Person(char *xname, int xage, int xsalary, char *xtel);
		void disp;
};

Person::Person(char *xname, int xage, int xsalary, char *xtel) {
	strcpy(name, xname);//给name赋值
	age = xage;
	salary = xsalary;
	strcpy(tel, xtel); 
}

void Person::disp() {
	cout<<endl;
	cout<<"姓名:"<<name<<endl;
	cout<<"年龄:"<<age<<endl;
	cout<<"工资:"<<salary<<endl;
	cout<<"电话:"<<tel<<endl;
}

void main() {
	Person mrzhang("张三", 25, 850, "12345678");
	mrzhang.disp();
}

(4)构造函数重载的例子:可见其匹配方式与普通函数重载的相同

#include <string.h>
#include <iostream>
using namespace std;

//构造函数的重载 
class Book{
	private:
		char name[20];
		int number;
	public:
		Book();//第一个构造函数说明 
		Book(char *newName, int number);//第二个构造函数说明 
		void show();
}; 

Book::Book() {
	strcpy(name, "no name");
	number = 0;
}

Book::Book(char *newName, int newNumber) {
			strcpy(name, newName);
			number = newNumber;
	}

void Book::show() {
			cout << "名称:"<<name<<endl;
			cout << "号码:"<<number<<endl;
	} 
	
int main() {
	//自动调用第二个构造函数 
	Book mybook("Visual C++6.0", 10020);
	mybook.show();
	
	//自动调用第一个构造函数 
	Book yourbook;
	yourbook.show();
	
	return 0;
}

(5)当构造函数有默认参数时,称为具有默认参数的构造函数,使用时要防止二义性

class Myclass{
	private:
		int number;
	public:
		Myclass();
		Myclass(int i = 10);
}; 

Myclass::Myclass() {
	member  = 10;
}

Myclass::Myclass(int i) {
	member  = i;
}

void main() {
	Myclass x(20);
	Myclass y;//此行产生二义性,无法确定调用哪个构造函数 
}

(6)构造函数的初始化表:可以在表中为数据成员赋初值

格式:类名(形参表):数据成员1(初值1),…

初值可以是常量或形参表中的参数

class Date{
	public:
		Date():year(2000), month(3), day(1) { }
		Date(int y, int m, int d):year(y), month(m), day(d) { }	
	private:
		int year, month, day;
}; 

(7)在构造函数的初始化表中,还可以调用其他构造函数,成为“委派构造函数

class Info {
	public:
		Info() { Init(); }
		Info(int i) : Info() { id = i; }
		Info(char c): Info() { gender = c; }
	private:
		void Init() { ... }//其他初始化
		int id {2016};
		char gender {'M'}; 
};

10.拷贝

(1)通过对象赋值实现拷贝

//同一个类生成的两个对象之间赋值,数据成员会赋值过去 
#include <Book.h>
void main {
	Book book1, book2;
	
	book1.regist("abc", 1001); 

	book2 = book1;
	
	book1.show(); //"abc", 1001
	book2.show(); //"abc", 1001 
        
}

(2)拷贝构造函数

定义格式:类名([const]类名 &形参) {函数体};

说明

  • 拷贝构造函数名与类名相同,只有一个参数,该参数就是对一个该类对象的引用
  • 功能:通过将一个同类型对象的值拷贝给另一个新对象,来完成对新对象的初始化
#include <string.h>
#include <iostream>
using namespace std;

class Book{
	private:
		char name[20];
		int number;
	public:
		//成员函数regist()的声明 
		void regist(char *newName, int newNumber);
		//成员函数show()的声明 
		void show();
}; 
    //成员函数regist()的定义 
	void Book::regist(char *newName, int newNumber) {
			strcpy(name, newName);//给数据成员name赋值
			number = newNumber;//给成员number赋值 
	}
	//成员函数show()的定义 
	void Book::show() {
			cout << "名称:"<<name<<endl;
			cout << "号码:"<<number<<endl;
	} 
//以上可以写成#include<Book.h> 

//拷贝构造函数
 class Point {
 	private:
 		int x, y;
 	public:
 		Point() { }
 		Point(int inx, int iny) {
 			x = inx;
 			y = iny;
		 }
		 Point(Point &p) {
		 	x = p.x;
		 	y = p.y;
		 	cout<<"执行拷贝构造函数"<<endl;
		 } 
		 void show(char *name) {
		 	cout<<endl;
		 			cout<<name
		 			<<"("<<x
		 			<<","<<y<<")"
		 			<<endl;
		 } 
 };
 
 void Print(Point p) {
 	p.show("");
 } 
 
int main() {
 	Point p1(1, 2), p2;
 	p2 = p1;
 	cout<<"执行对象间的赋值"<<endl;
 	
 	Point p3(p1);//执行拷贝构造函数
 	
 	p1.show("p1");//p1(1,2)
 	p1.show("p2");//p2(1,2)
 	p1.show("p3");//p3(1,2)
 	
 	Point p4 = p1;
	cout<<endl<<"p4";//p4 
	Print(p4);//执行拷贝构造函数(1,2)
	
	return 0;
 }

若未提供显式拷贝构造函数,则系统自动提供默认拷贝构造函数,功能是把作为参数的对象的数据成员逐个拷贝到目标对象中,称为成员级复制(浅拷贝)

#include <string.h>
#include <iostream>
using namespace std;

class Person {
	private:
		char *name;
		int num;
	public:
		Person(int i, char *str) {//浅拷贝函数
			name = new char[strlen(str) + 1];
			strcpy(name, str);
			num = i; 
		}
		void show() {
			cout<<"name = " << name <<endl;
			cout<<"num = " << num <<endl;
		}
		void SetName(char *str) {
			strcpy(name, str);
		}
		void SetNum(int n) {
			num = n;
		}
};

int main() {
	//调用函数Person(int i, char *str) 
	Person person1(215, "a");
	//使用拷贝构造函数构造person2(默认的) 
	Person person2(person1); 
	
	//更新person2的name
	person2.SetName("b");
	person2.SetNum(216);
	
	cout<<"Person1:"<<endl; 
	person1.show();
	cout<<"Person2:"<<endl; 
	person2.show();
	
	//输出:
	//Person1:
	//name = b
	//num = 215
	//Person2:
	//name = b
	//num = 216 
}

深拷贝

public:
		Person(const Person &x) {//深拷贝函数 
			name = new char[strlen(x.name) + 1];
			strcpy(name, x.name);
			num = x.num;
		}
	//输出:
	//Person1:
	//name = a
	//num = 215
	//Person2:
	//name = b
	//num = 216 

11.移动构造函数(*)

(1)语法:ClassName(ClassName&&);

(2)目的

偷临时变量中的资源(如内存)

临时变量被编译器设置为常量形式,使用拷贝构造函数无法将资源偷出来

12.析构函数

(1)定义格式:~类名(){函数体};

(2)特点:是类的特殊成员函数,一个类只能有一个析构函数,不能重载;无返回值,无参数,在对象生命期结束时,被系统自动调用

(3)功能:当对象使用完毕后,占用的系统资源需要在对象消失前被释放

(4)默认析构函数:未提供时提供默认的,~类名(){}。一般用默认的就行,但如果在类的对象中有动态分配的内存(如用new申请分配的内存)时,必须为该类提供析构函数。

#include <string.h>
#include <iostream>
using namespace std;

class Teacher {
	private:
		char *name;
		int age;
	public:
		Teacher(char *newName, int newAge) {
			//用new为name对象分配堆内存
			name = new char[strlen(newName) +1];
			strcpy(name, newName);
			age = newAge;
			cout<<"执行构造函数Teacher()"<<endl; 
		};
		~Teacher() {
			delete name;
			cout<<"执行析构函数~Teacher()"<<endl;
		} ;
		void show(); 
};
void Teacher::show() {
	cout<<"姓名:"<<name<<endl<<"年龄:"<<age<<endl;
}

int main() {
	Teacher teacher("a",25);
	teacher.show();
	cout<<endl;
	return 0;
}

//输出
//执行构造函数Teacher()
//姓名:a
//年龄:25
//执行析构函数~Teacher() 啥时候执行的?

13.堆对象

  • 用new和delete乐意动态分配或释放堆内存
  • 可以用new建立对象(会自动调用构造函数)
  • 利用delete可删除对象(会自动调用析构函数)
  • 堆对象一旦创建就一直存在,直到程序运行结束,可能被自动销毁,或用delete释放
#include <string.h>
#include <iostream>
using namespace std;

class TDate {
	public:
		TDate(int m, int d, int y);
		void show();
	private:
		int month, day ,year;
};

TDate::TDate(int m, int d, int y) {
	month = m; day = d; year = y;
}
void TDate::show() {
	cout<<month<<"/"
		<<day<<"/"
		<<year<<endl;
}

int main() {
	TDate *pd;
	pd = new TDate(1, 1, 1998);
	pd->show();
	delete pd;
	return 0;
}

14.对象数组

(1)定义:一个数组的类型除了可以为基本都数据类型外,还可以为类类型,则该数组中的每个元素都是该类的一个对象

(2)定义格式:类名 数组名[数组大小]

//第一种方法
#include <string.h>
#include <iostream>
using namespace std;

class Person {
	private:
		char *name;
		int age;
	public:
		Person();
		~Person();
		void assignment(char *a, int b);
		void show();
};

Person::Person() {
	name = new char('\0');
	age = -1;
}
Person::~Person() {
	delete[] name;
}
void Person::assignment(char *a, int b) {
	name = new char[strlen(a) + 1];
	strcpy(name, a);
	age = b;
};
void Person::show()  {
	cout<<"\n  姓名:"<<name<<"年龄:"<<age;
};

int main() {
	//定义对象数组
	Person employee[5];
	
	//赋值
	employee[0].assignment("a", 25); 
	employee[1].assignment("b", 25); 
	employee[2].assignment("c", 25); 
	employee[3].assignment("d", 25);
	employee[4].assignment("e", 25); 
	
	int i;
	for(i = 0; i < 5; i++) {
		employee[i].show();
	}
	return 0;
	
	return 0;
}


//第二种初始化数组方法

class Person {
	private:
		char *name;
		int age;
	public:
		Person();
		~Person();
		Person(char *a, int b);
		void show();
};

Person::Person() {
	name = new char('\0');
	age = -1;
}
Person::~Person() {
	delete[] name;
}

Person::Person(char *a, int b) {
	name = new char[strlen(a) + 1];
	strcpy(name, a);
	age = b;
};
void Person::show()  {
	cout<<"\n  姓名:"<<name<<"年龄:"<<age;
};

int main() {
	Person employee[5] = {
		Person("a", 25),
		Person("b", 25),
		Person("c", 25),
		Person("d", 25),
		Person("e", 25)
	} ;
	
	int i;
	for(i = 0; i < 5; i++) {
		employee[i].show();
	}
	return 0;
} 

15.类作用域

(1)定义:在类定义包括的范围

(2)小于文件域,大于函数域

(3)在类域内定义的变量不能使用auto、register和extern等修饰符

(4)在类域内定义的静态数据成员和静态成员函数具有外部的链接属性

#include <string.h>
#include <iostream>
using namespace std;

class Myclass {
	private:
		int x;
		int y;
	public:
		Myclass(int a, int b) {
			x = a; y = b;
		}
		void print();
		void myfunc();
}; 

void Myclass::print() {
	cout<<"x="<<x<<","<<"y="<<y<<endl;
}

//①类中的成员具有类作用域,在成员函数中可以直接引用类的数据成员。但如果在成员函数中定义了同名的局部变量,就要用::区分
//②在类的定义外,由于不同的成员函数可以具有相同的名字,因此需要用::指明该成员函数所属的类
void Myclass::myfunc() {
	int x = 9, y = 10;
	
 
        
	//输出局部变量
	cout<<"In myfunc:x ="<<x<<","<<"y="<<y<<endl;
	
	//输出类的数据成员
	cout<<"Myclass::x="<<Myclass::x <<","<<"Myclass::y="<<Myclass::y<<endl;
} 

int main() {
        //③在类外访问类的成员时,必须通过对象名或指向对象的指针。对象名用.,指针用->
	Myclass test(100, 200), *ptest = &test;
	test.print();//通过对象名访问公有成员
	ptest->myfunc();//通过指向对象的指针访问共有成员 
	
}

16.对象成员

(1)定义:一个类的对象作为另一个类的数据成员

(2)定义格式:class x { 类名1 对象1;…其他对象成员};

(3)这是类之间的包含关系has-a

(4)初始化:如果类A的对象是类B的数据成员,那么在创建类B的对象时,类A的对象也会被自动创建

(5)包含对象成员的对象的初始化:在构造类B的对象时,首先调用类A的构造函数,初始化对象成员,再执行类B自己的构造函数,初始化类中的非对象成员;对于同一类中的多个对象成员,按类中说明顺序调用相应构造函数进行初始化

(6)若类A的构造函数为有参,则必须在B的初始化表中指明A的构造函数和参数。参数表1提供初始化成员1所需参数,这几个参数表中的参数均来自参数表0,初始化B的非对象成员所需的参数吗,也来自参数表0

B::B(参数表0):成员1(参数表1),成员2(参数表2),…

#include <string.h>
#include <iostream>
using namespace std;

class Student {
	public:
		Student() {
			cout<<"构造函数Student()"<<endl; 
		}
}; 
class Teacher {
	public:
		Teacher() {
			cout<<"构造函数Teacher()"<<endl; 
		}
}; 
class Tourpair {
	public:
		Tourpair() {
			cout<<"构造函数Tourpair()"<<endl; 
		}
	protected:
		Student student;
		Teacher teacher;
}; 
int main() {
	Tourpair tp;
	cout<<"回到main函数"<<endl;
	return 0;
}
//输出:
// 构造函数Student()
// 构造函数Teacher()
// 构造函数Tourpair()
// 回到main函数

例:对象成员的初始化

#include <string.h>
#include <iostream>
using namespace std;

class Student {
	protected:
		char name[40]; 
	public:
		Student(char *pName = "Noname") {
			cout<<"构造函数Student:"<<pName<<endl;
			strncpy(name, pName, sizeof(name));
			//strncpy(char *dest, const char *src, size_t n) 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
			name[sizeof(name-1)] = '\0';
		}
		Student(Student &s) {
			cout<<"拷贝构造Student:"<<s.name<<"的克隆"<<endl;
			strcpy(name, s.name);
			strcat(name, "的克隆"); 
		}
		~Student() {
			cout<<"析构Student:"<<name<<endl;
		}
}; 

class Tutor {
	protected:
		Student student;
	public:
		Tutor(Student &s) :student(s) {//这是初始化表,调用student的拷贝构造函数 
			cout<<"构造函数Tutor()"<<endl; 
		}
		~Tutor() {
			cout<<"析构Tutor:"<<endl;
		}
}; 


int main() {
	Student st1;//此处调用Student的构造函数 Student(char *pName = "Noname")
	Student st2("LiHai");//同上
	
	// 此处调用Tutor的构造函数 Tutor(Student &s)
	//在构造tutor对象的过程中,用初始化表调用
	//Student类的拷贝构造函数Student(Student &s)
	Tutor tutor(st2); 
	return 0;
}
//输出
//构造函数Student:Noname
//构造函数Student:LiHai
//拷贝构造Student:LiHai的克隆
//构造函数Tutor()
//析构Tutor:
//析构Student:LiHai的克隆
//析构Student:LiHai
//析构Student:Noname 

17.常量数据成员的初始化

对象的数据成员初始化——用构造函数。但如果是常量成员或引用成员,就不行了,只能用初始化表。

class Sillyclass {
	//该构造函数初始化方法不正确 
//	public:
//		sillyclass(int i) {
//			ten = 10;
//			refi = 1;
//		}
		
	//下面是对的初始化方式
	public:
		sillyclass(int i):ten(10), refi(i) {} 
	protected:
		const int ten;//常量数据成员
		int &refi;//引用成员 
};

18.常成员函数

声明和定义格式

class 类名 {
	类型 函数名{参数表} const; //const可以参与区分重载函数 
}; 
类名::函数名{参数表} const {
} 
  • 为只读函数,可以读取数据成员的值,但不能修改
  • 不能调用类中其他非常成员函数

19.常对象(对象常量)

定义格式:const 类名 对象名; 类名 const 对象名;

class X {
	private:
		int m;
	public:
		void SetM(int inVal);
		int GetM();
};
void X::SetM(int inVal) {
	m = inVal;
}
int X::GetM() {
	return m;
}

void main() {
	const X obj;//警告 
	//不能调用常对象的非const型的成员函数
	obj.SetM(10);//报错 
	obj.GetM();//报错 
}

20.静态成员

静态成员包括静态数据成员和静态成员函数,是同一个类的所有对象公有的

(1)静态数据成员

  • 定义static 类型说明符 成员名,例如在public中static int count;
  • 赋初值语句写在全局中,必须指明类,在类外int Visitor::count = 0;
  • 在一个类的对象空间中,不包含静态成员的空间,所以静态成员空间不会随着对象产生和消失而变化
  • 静态数据成员的空间在程序开始运行时就被分配
  • 对于在类的public中说明的静态数据成员,可以不使用成员函数而直接访问,即使未定义类的对象也可以直接访问,但要指明所属的类,如在main中cout<<Visitor::count;
  • private和protected中的静态成员只能通过类的成员函数访问
#include <iostream>
#include <string.h>
using namespace std;

class Visitor {
	private:
		char *name;
		int serial_number;
	public:
		static int count;
		void Regist(char *a);
};
int Visitor::count = 0;//静态变量赋初值 
void Visitor::Regist(char *a) {
	name = new char[strlen(a)+1];
	strcpy(name, a);
	serial_number = ++count;
	cout<<"编号:"<<serial_number<<endl;
} 

int main() {
	Visitor visitor[3];//定义对象数组
	int i;
	char str[8]; 
	cout<<endl;
	for(i = 0; i < 3; i++) {
		cout<<"输入姓名:";
		cin>>str;
		visitor[i].Regist(str);
	}
	cout<<endl;
	cout<<Visitor::count;
	return 0;
}

(2)静态成员函数

  • 定义:static 类型 函数名(形参){函数体};
  • 访问静态成员函数时,可以不需要对象
  • 静态成员函数不能访问非静态成员
#include <iostream>
using namespace std;

class objcount {
	private:
		static int count;
	public:
		objcount() {
			count++;
		}
		static int get() {
			return count;
		}
};
int objcount::count = 3;//静态变量赋初值 

int main() {
	cout<<objcount::get()<<endl;
	objcount a, b, c, d, e, f;
	//静态成员函数可以通过类名引用 
	cout<<objcount::get()<<endl;
	//也可以通过对象名引用 
	cout<<a.get()<<endl;
}

21.友元

(1)友元

  • 不是类的成员函数,能访问一个或多个类的所有成员
  • 定义:类内或类外
  • 声明:类内,需要在各个类中分别声明,friend 名称

(2)友元函数

  • 声明:friend 函数类型 函数名(类名 参数);
  • 一个类的友元函数与成员函数一样,有对该类成员的访问权
  • 不允许将某个类的构造函数、析构函数、虚函数声明为友元函数
  • 可以把另一个类的公有成员函数声明为自己的友元函数

(3)友元类

  • 若类A被说明为类B的友元类,则类B的成员就可以被类A的成员访问
  • 定义:在classB中写friend class A;
  • 友元类的所有成员函数都可视为该类的友元函数,能存取该类的私有成员和保护成员
  • 没有对称性和传递性

22.子对象

子对象的初始化在构造函数的成员初始化列表中进行

class C3 {
    int num;
    C1 obj1;
    C2 obj2;
};
调用构造函数:C1->C2->C3
调用析构函数:C3->C2->C1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值