2020-02-14 C++核心编程03-基本框架

4.2.8静态成员

静态成员变量

1.所有对象共享同一份数据;

2.在编译阶段分配内存;

3.类内声明,类外初始化;

示例:

class Person

{

public:

public:

static int _A;

//静态成员变量,不属于某个对象上,所有对象都共享同一个数据

//静态成员变量具有两种访问方式

//1.通过对象进行访问

//2.通过类名进行访问

//静态成员变量也是有访问权限的

private:

static int _B;//类内声明

};

int Person::_A=100;

int Person::_B = 200;//类外初始化

void test02()

{

//通过类名访问静态成员变量

cout << Person::_A << endl;

//cout << Person::_B << endl;类外访问不到私有(保护)静态成员变量

}

静态成员函数

1.所有对象共享同一个函数;

2.静态成员函数只能访问静态成员变量;

示例:

class Person

{

public:

static void func()//静态成员函数也是有访问权限的

{

_A = 100;//静态成员函数可以访问 静态成员变量

//_B = 200;//静态成员函数不可以访问 非静态成员变量

        //因为无法区分到底是哪个对象的_B

cout << "static void func()" << endl;

}

public:

static int _A;

int _B;

private:

static void func2()

{

cout << "static void func2()" << endl;

}

};

int Person::_A = 0;

void test01()

{

Person p;

p.func();//1.通过对象访问

cout << "-------" << endl;

Person::func();//2.通过类名访问

}

void test02()

{

//Person::func2();//类外访问不到私有的静态成员函数

}

4.3C++对象模型和this指针

4.3.1成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上

4.3.1this指针

每个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码

C++通过提供特殊的对象指针,this指针,能够使得代码区分调用自己的对象

概念:

1.this指针指向被调用的成员函数所属的对象;

2.this指针是隐含每一个非静态成员函数的一种指针;

3.this指针不需要定义,直接使用即可;

用途:

1.当形参和成员变量同名时,可用this指针来区分;(解决名称冲突)

2.在类的非静态成员函数中返回对象本身,可使用 return *this;

示例:

class Person

{

public:

Person(int age)

{

//1.解决名称冲突

//age = age;//error ,编译器认为两个age是同一个,即形参age

//this指针指向的是被调用成员函数所属的对象

this->age = age;

}

void PersonAddAge(Person &p)

{

this->age += p.age;

}

//易错点

//Person PersonAddAge2(Person &p)

//error

Person & PersonAddAge2(Person &p)

{

this->age += p.age;

//this是指向p2的指针,而*this就是p2这个对象本体

return *this;

}

Person  PersonAddAge3(Person &p)

{

this->age += p.age;

//this是指向p2的指针,而*this就是p2这个对象本体

return *this;

}

int age;

};

void test01()

{

Person p1(18);

cout << "the age of p1 is " << p1.age << endl;

}

//2.返回对象本身用*this

void test02()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge(p1);

cout << "the age of p2 is " << p2.age << endl;

//p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);

//error

}

void test03()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge2(p1);

cout << "the age of p2 is " << p2.age << endl;

//链式编程思想

p2.PersonAddAge2(p1).PersonAddAge2(p1).PersonAddAge2(p1);

cout << "the age of p2 is " << p2.age << endl;

}

void test04()

{

Person p1(10);

Person p2(10);

p2.PersonAddAge3(p1);//p2.age更改,但函数返回的是p2的拷贝

                    //此时p2.age=20

cout << "the age of p2 is " << p2.age << endl;

//第一个函数更改了p2.age 但返回的是p2的拷贝 记为 p2’

//第二个函数更改的是p2’

//第三个函数更改的是p2''

//所以p2.age=30

p2.PersonAddAge3(p1).PersonAddAge3(p1).PersonAddAge3(p1);

cout << "the age of p2 is " << p2.age << endl;

}

4.3.3空指针访问成员函数

C++中空指针也可以调用成员函数,但要注意有没有用到this指针

如果用到this指针,需要加以判断保证代码健壮性

示例:

class Person

{

public:

//空指针可以正常访问

void showClassName()

{

cout << "this is Person class" << endl;

}

void showPersonAge()

{

//报错原因是因为传入的指针为NULL

cout << "age is " << m_Age << endl;

//m_Age默认为this->m_Age

}

void showPersonAge2()

{

//提高代码健壮性

if (this == NULL)

{

return;

}

cout << "age is " << m_Age << endl;

}

int m_Age;

};

void test01()

{

Person *p = NULL;

p->showClassName();

//p->showPersonAge();

//error

p->showPersonAge2();

}

4.3.4const修饰成员函数

常函数:

1.成员函数后加const后我们称这个函数为常函数;

2.常函数内不可以修改成员属性;

3.成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象:

1.声明对象前加const称该对象为常对象;

2.常对象只能调用常函数;

示例:

class Person

{

public:

void showPerson1()

{

//this指针本质是指针常量,指针的指向是不可以修改的

//Person * const this;

this->m_A = 100;//this指针指向的内容可以修改

//this = NULL;//this指针不可以修改指针指向

}

//在成员函数后面加上const 修饰的是this指针,让指针指向的值也不可以修改

void showPerson2() const  //常函数

{

//如果想要this指针指向的值也不可以修改

//把const加在成员函数后

//就相当于const Person * const this;

    //this->m_A = 100;//error

this->m_B = 100;//ok

}

public:

int m_A;

mutable int m_B;//特殊变量,即使在常函数中,也可以修改这个值

                //加关键字mutable

};

void test01()

{

//常对象

const Person p;

//p.m_A = 100;//error

p.m_B = 100;//ok ,m_B是特殊值,在常对象下也可以修改

    //常对象只能调用常函数

//不可以调用普通成员函数,因为普通成员函数可以修改属性

//p.showPerson1();//error

p.showPerson2();//ok

}


4.4友元

目的:让一个函数或类 访问另一个类中的私有成员

关键字:friend

友元的三种实现:

1.全局函数做友元函数

2.类做友元类

3.类的成员函数做友元

4.5运算符重载

概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

4.5.1加号运算符重载

作用:实现两个自定义数据类型相加的运算

两种方式:

1.成员函数重载

2.全局函数重载

示例:

class Person

{

public:

//Person operator+(Person &p);//1.成员函数重载

Person(){}

Person(int a, int b);

public:

int m_A;

int m_B;

};

//Person Person::operator+(Person &p)

//{

// Person temp;

// temp.m_A=this->m_A + p.m_A;

// temp.m_B=this->m_B + p.m_B;

// return temp;

//}

Person::Person(int a, int b)

{

m_A = a;

m_B = b;

}

//2.全局函数重载

Person operator+(Person &p1, Person &p2)

{

Person temp;

temp.m_A = p1.m_A + p2.m_A;

temp.m_B = p1.m_B + p2.m_B;

return temp;

}

//运算符重载,也可以发生函数重载

//函数重载的版本

Person operator+(Person &p1, int a)

{

Person temp;

temp.m_A = p1.m_A + a;

temp.m_B = p1.m_B + a;

return temp;

}

void test00()

{

Person p1(10, 10);

Person p2 = p1 + 10;

cout << "p2.m_A=" << p2.m_A << endl

<< "p2.m_B=" << p2.m_B << endl;

}

void test01()

{

Person p1(10, 10);

Person p2(20, 20);

Person p3 = p1 + p2;

//1.成员函数重载的本质调用

//Person p3=p1.operator+(p2);

//2.全局函数重载的本质调用

//Person p3=operator+(p1,p2);

}

总结:

1.对于内置的数据类型的表达式的运算符是不可能改变的;

2.不要滥用运算符重载;

4.5.2左移运算符重载

作用:输出自定义数据类型

注意:只能通过全局函数重载输出流运算符,且需要设置为类的友元函数

示例:

class Person

{

//将全局函数设置为友元

friend ostream & operator<<(ostream &os, Person &p);

public:

//利用成员函数重载 左移运算符 p.operator<<(cout) 简化版本 p<<cout

//不会利用成员函数重载<<运算符 ,因为无法实现cout在左侧

//void operator<<(cout ){}

    Person(int a, int b)

{

m_A = a;

m_B = b;

}

private:

int m_A;

int m_B;

};

//只能利用全局函数重载左移运算符

//void  operator<<(ostream &cout,Person &p)//本质 operator<<(cout,p) 简化 cout<<p

//{

// cout << "m_A=" << p.m_A << endl

// << "m_B=" << p.m_B << endl;

//}

//ostream 也是一种类

//ostream对象只能有一个,所以需要加&

ostream & operator<<(ostream &os, Person &p)//本质 operator<<(cout,p) 简化 cout<<p

{

os << "m_A=" << p.m_A <<"  "

<< "m_B=" << p.m_B ;

return os;

}

void test01()

{

Person p(10,10);

//cout << p ;

cout<<p<<endl;

//返回值为void时,上一行程序会崩掉

//由于左侧返回的是void ,不能实现链式编程

//因此需要对左移运算符重载函数进行返回值的修改

}

总结:重载左移运算符配合友元可以实现输出自定义数据类型

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容