c++ primer 第七章
类的作用域:
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。在类中声明的类型,在main函数中也可以拿来用
class Screen{ public: typedef std::string::size_type index; };
Screen::index get_name()//值得借鉴
{
return 0;
}
int main() { Screen::index ht;//此方法值得借鉴 return 0; }
作用域:全局作用域、类作用域、函数作用域??
int height; class Screen { public: typedef std::string::size_type index; void dummy_fcn(index height) { cursor = width * height;//这是哪个height,隐藏 //cursor = width * this->height; //cursor = width * ::height;//使用全局height方法 } private: index cursor; index height, width; };
构造函数
作用:保证每个对象的数据成员具有合适的初始值
构造函数初始化形式(初始化列表)??
构造函数函数名没有类型,对其数据成员进行初始化,没写的默认初始化,内置类型不进行初始化
默认实参与构造函数??
构造函数永运不需要声明为const,
普通函数看情况
默认构造函数??
构造函数要写,因为类型是内置类型,初始化的时候是不进行默认初始化,默认构造函数将不存在。
初始化列表比赋值效率高??
系统会自动进行初始化,再用this->name = name;则进行一次赋值,效率下降
class Dog { public: Dog():legs(4)//内置类型不进行默认初始化 { //this->legs = 4;常量必须初始化 } private: std::string name; // const int legs = 4; const int legs;//只能用初始化列表,不能用赋值进行初始化 };
初始化顺序为类数据成员的顺序,而非初始化列表顺序
初始化列表初始化有??
const类型,引用类型,没有默认构造函数的类类型
隐式类类型转换??(只对于含有一个参数时产生的副作用)
构造函数含有一个参数时,隐式的将参数转变为对象,很可怕,前面加上explicit
explicit Sale_item(std::istream &is) { is >> *this; }
构造函数的功能合并??
初始化个空值,当对象没有参数是就使用这个空值,有参数,使用初始化列表
class Sale_item{ public: Sale_item(const std::string &book=" "):isbn(book),units_sold(0),revenue(0,0) {} //等同将构造函数Sale_item的功能合并了 private: //略 }; Sale_item a; Sale_item a("35535 ")
注意了:调用默认构造函数不要(),Sale_item();是错误的,这是函数的声明了,哈哈
Sale_item *p = new Sale_item(); //或者Sale_item *p = new Sale_item; delete p;//*p错误,删除地址
类的定义1
类声明->前向声明
类的前置声明,只声明了类,不可以定义个对象,但能定义指针和引用(但没有绑定的对象)
//可以相互定义,前提是声明了Y,因为类X中指针有用到类Y class Y; //类的前置声明 class X { //各种成员略 private: Y *ptr; }; class Y { //各种成员略 private: X *ptr; X obj; };
类对象:
Record r("xiaoming");//在堆栈上创建类的对象 Record *p = new Record;//在堆上动态的创建对象 Record *p = new Record; class Record r2;//沿用c //C++有严格要求,用new创建对象时,用delete进行删除 delete p;
演变:
C -> C++(带类的C)
c语言中能写的,在C++中都能写
问题:
当有两个相同的构造函数时(名称和参数都相同),出现错误,不知道哦调用哪个
Record(std::string na):name(na) {} //显示形参只有一个,却默认初始化有两个 Record(std::string na) :name(na), byte_count(0) {}
实践代码:
#include<iostream> #include<string> using namespace std; //类的前置声明,不可以定义个对象,但能定义指针和引用(没有对象) class Y; class X { //各种成员略 private: Y *ptr; }; class Y { //各种成员略 private: X *ptr; X obj; }; class Screen; class LinkScreen { //Screen window;不可,Screen还未定义,成员 Screen *window; LinkScreen *next;//指向自己 LinkScreen *prev; }; //记录 class Record //这是一个完整的类,即是类定义,又是类声明 { public: Record():byte_count(0) {} /* 已经有一个与之一样的构造函数了,错误 Record(std::string na):name(na) {} */ //显示形参只有一个,却默认初始化有两个 Record(std::string na) :name(na), byte_count(0) {} //写在一行也很好 std::string get_name() const { return name; } string::size_type get_byte_count() const { return byte_count; } private: std::string name; string::size_type byte_count; }r3;//传统c语言写法,还有class 换成struct,区别在于默认,c中没有私有成员 int main() { Record r("xiaoming");//在堆栈上创建类的对象 Record *p = new Record;//在堆上动态的创建对象 class Record r2;//沿用c //C++有严格要求,用new创建对象时,用delete进行删除 delete p; cout << r.get_name()<<r.get_byte_count() << endl; return 0; }
类的定义2
将类的数据成员定义为共有成员,可以直接使用,但不符合类的封装原则。
public: std::string name;
当函数不修改时,只读不修改数据将其定义为const函数,内容较少时,写在同一行
std::string get_name() const { return name; } string::size_type get_byte_count() const { return byte_count; }
初始化列表比赋值要快,可读性更好
//显示形参只有一个,却默认初始化有两个 Record(std::string na) :name(na), byte_count(0) {}
Screen(index ht=0,index wt=0):content(ht*wt,'A'),cursor(0),height(ht),width(wt) { //初始化字符串content(ht*wt,'A'),构造函数没写参数没代表没有,默认而以 }
创建一个函数时候,将框架写出来,return 紧跟其后
bool same_isbn(Sale_item &rh) const { return }
类中的成员,类中可直接调用
bool same_isbn(Sales_item &rh) const { //虽然isbn是私有成员,但在类中可以直接调用 return isbn == rh.isbn; /*if (isbn == rh.isbn) return 0; else return -1;*/ }
#include <iostream> #include <string> using namespace std; class People { public: //构造函数,初始化列表,效率比赋值快 People(const std::string &nm):name(nm) { } std::string getName() const { return name; }; private: std::string name; }; class Sales_item { public: //构造函数 Sales_item(std::string bookno, unsigned amount, double total) :isbn(bookno), units_sold(amount), revenue(total) { } //成员函数,计算平均多少钱 double avg_price() const { if (units_sold) return revenue / units_sold; else return 0; } //成员函数,判断两个销售单是不是同一本数 bool same_isbn(Sales_item &rhs) const { //虽然isbn是私有成员,但在类中可以直接调用 return isbn == rhs.isbn; /*if (isbn == rh.isbn) return 0; else return -1;*/ } //将两个销售单进行相加 unsigned add(const Sales_item &rhs) //不能定义为const { units_sold +=rhs.units_sold; return units_sold ; } unsigned total() { return units_sold; } private: std::string isbn;//书号 unsigned units_sold;//销售数量 double revenue;//总金额 }; int main() { /*People m("Wang Dongyu"); cout << m.getName();*/ Sales_item b1("95533", 5, 30); Sales_item b2("95533", 6, 25); if (b1.same_isbn(b2)) b1.add(b2); cout <<b1.total()<<'\n'<<b1.avg_price()<<endl; return 0; }
问题一:size_t和size_type区别
为了使自己的程序有很好的移植性,c++程序员应该尽量使用size_t和size_type而不是int, unsigned
1. size_t是全局定义的类型;size_type是STL类中定义的类型属性,用以保存任意string和vector类对象的长度
2. string::size_type 制类型一般就是unsigned int, 但是不同机器环境长度可能不同 win32 和win64上长度差别;size_type一般也是unsigned int
3. 使用的时候可以参考:
string::size_type a =123;
vector<int>size_type b=234;
size_t b=456;
4. size_t 使用的时候头文件需要 <cstddef> ;size_type 使用的时候需要<string>或者<vector>
5. sizeof(string::size_type)
sizeof(vector<bool>::size_type)
sizeof(vector<char>::size_type)
sizeof(size_t)
上述长度均相等,长度为win32:4 win64:8
6. 二者联系:在用下标访问元素时,vector使用vector::size_type作为下标类型,而数组下标的正确类型则是size_t
类的定义3
同一类型的多个数据成员??
index height, width;
使用类型别名来简化类??
typedef std::string::size_type index;
成员函数可被重载-定义重载成员函数??
char get_cursor() const;
char get_cursor(index r, index c) const
显法指定inline成员函数??
三种方法,类联函数运行快
i.类中写,默认
ii.函数声明加inline
iii.类外定义前加inline都行,成员函数前指明属于哪个类
问题一:
Screen(index ht=0,index wt=0):content(ht*wt, 'A'),cursor(0),height(ht),width(wt)
{
//初始化字符串content(ht*wt,'A'),构造函数没写参数没代表没有,默认而以
}
问题二:
找不到匹配的构造函数
解决方法1.除去&,2加上const
问题三:何时用&符号??
待解决
#include<iostream> #include<string> using namespace std; class Screen { //使用类别名进行简化 typedef std::string::size_type index; public: //构造函数 /*Screen(const std::string str, index cur, index r, index c):content(str),cursor(cur),height(r),width(c) {}*/ Screen(index ht=0,index wt=0):content(ht*wt, 'A'),cursor(0),height(ht),width(wt) { //初始化字符串content(ht*wt,'A'),构造函数没写参数没代表没有,默认而以 } //Screen(index ht = 0, index wt = 0, std::string &conts);错误默实参不在形参末尾 Screen( std::string conts,index ht, index wt); //函数声明 char get_cursor() const; //重载函数,类联函数 inline char get_cursor(index r, index c) const; private: std::string content; //字符串 index cursor;//光标位置 index height, width;//文本框的宽度和高度 }; //类外部构造函数 inline Screen::Screen(std::string conts,index ht, index wt) :content(conts), cursor(0), height(ht), width(wt) {} //返回光标位置 char Screen::get_cursor() const { return content[cursor]; } //inline char Screen::get_cursor(index r, index c) const char Screen::get_cursor(index r, index c) const { std::string::size_type row = r * width; return content[row + c]; } int main() { Screen a(100,50); Screen b("my favorite subject is c++",6,13); cout << a.get_cursor() << endl;//a cout << a.get_cursor(5, 7) << endl;//a cout << b.get_cursor() << endl;//m cout << b.get_cursor(0, 6) << endl;//o空格不算 return 0; }
隐含的this指针
#include<iostream> #include<string> using namespace std; class Person { public: Person(const std::string &na,const std::string &ad):name(na),skill(ad) { /* this->name = na; this->skill = ad; */ } //无需定义this指针,c++隐含,表示指向当前对象*this.name std::string get_name() const { return this->name; } std::string get_skill() const { return this->skill; } private: std::string name; std::string skill; }; int main() { Person hero("红玉", "封喉"); cout << hero.get_name() << hero.get_skill() << endl; return 0; }
何时使用this指针??
Person(const std::string &name,const std::string &address):name(na),skill(ad) { this->name = name;//若不行this,c++就傻傻分不清 this->skill = address; }
返回*this??
从const成员函数返回*this??
//返回Screen对象,并能修改
Screen& display(std::ostream &os) { do_display(os); return *this; } //const是个常量,返回Screen对象,但不能修改函数的数据成员
//函数是const,声明类型也要const
基于const的重载??可变数据成员??
思考为什么前面也要加const??
const Screen& dispaly(std::ostream &os) const { ++access_ctr;//const本身不能修改其数据成员,得先声明为 mutable size_t do_display(os) return *this }
友元
三种友元??
1.普通函数
2.类
3.类的成员函数
class Screen { public: //类的友元函数的声明 friend int caluArea(Screen &); //友元类,可以访问类的所有成员 friend class Window_Mar; //声明另外一个类中的部分友元函数 friend int Dog::foo(Screen&); }; //友元函数 int caluArea(Screen &screen) { return screen.height * screen.width; } //友元类 class Window_Mar { public: void relocate(int r, int c, Screen &s)//Screen没找到 { s.height += r; s.width += c; } }; //类中的部分友元函数 class Dog { public: int foo(Screen &screen) { return screen.height*screen.width; } void koo(Screen& screen) {} };
类和友元相互依赖,声明和定义,使用了却没有找到定义,该如何处理??
class Screen; //类中的部分友元函数 class Dog { public: int foo(Screen &screen); void koo(Screen& screen); }; //省略Screen类 //注意命名空间不要丢 int Dog::foo(Screen &screen) { return screen.height * screen.width; } void Dog::koo(Screen& screen){}
实践代码:
#include<iostream> #include<string> using namespace std; /* 虽然加了声明,但还是没有进行定义,友元类无法定义 class Screen; class Window_Mar { public: void relocate(int r, int c, Screen &s)//Screen没找到 { s.height += r; s.width += c; } }; */ class Screen; //类中的部分友元函数 class Dog { public: int foo(Screen &screen); void koo(Screen& screen); }; class Screen { public: //类的友元函数的声明 friend int caluArea(Screen & ); //友元类,可以访问类的所有成员 friend class Window_Mar; /* 声明另外一个类中的部分友元函数, 但此时还见不到Dog */ friend int Dog::foo(Screen&); typedef std::string::size_type index; Screen(int ht=0, int wd=0):contents(ht*wd,' '),cursor(0),height(ht),width(wd) {} int area() const { return height * width; } private: std::string contents; index cursor; int height, width; }; //友元函数 int caluArea(Screen &screen) { return screen.height * screen.width; } //友元类 class Window_Mar { public: void relocate(int r, int c, Screen &s)//Screen没找到 { s.height += r; s.width += c; } }; //注意命名空间不要丢 int Dog::foo(Screen &screen) { return screen.height * screen.width; } void Dog::koo(Screen& screen){} int main() { Screen a(50, 20); cout << a.area() << endl; cout << caluArea(a) << endl;//1000 Window_Mar wm; wm.relocate(20, 100, a); cout << caluArea(a) << endl;//8400 Dog d; cout << d.foo(a) << endl; return 0; }
static 类成员
多用静态成员,少用全局变量、全局函数、全局对象
使用类的static成员的优点??
1.两个类中的静态成员即使同名也互不影响,静态成员的作用域在类中
2.可以私有封装
3.在未创建对象时,就可以对其进行修改
定义static成员??使用类的static成员??static成员函数??static数据成员??
#include<iostream> #include<string> using namespace std; /* 全局变量来保存利率 double interestRate; 此办法不好,所有的类,函数都可以使用 */ class Account { public: Account(std::string name,double money):owner(name),amount(money) {} double getAmount() const { return this->amount; } void applyint() { amount += amount * interestRate; } void deposit(double money) { this->amount += money; } /* 如何改变利率,私有成员得通过共有函数修改?? 静态变量最好用静态的函数操作!! 静态函数的好处?? 类+作用域操作符+函数();未创建对象就能对其修改 静态成员不能使用this指针?? this指针指向当前对象,而静态成员是大家的,不属于任何一个对象 */ static double rate() { return interestRate; } static void rate(double newRate) { interestRate = newRate; } private: std::string owner; double amount;//a对象有一个,b对象有一个 static double interestRate;//只有一个 /* double interestRate; 此办法也不好,当需要修改利率时,得将所有的对象都进行修改 static double interestRate = 0.015不可以在这里初始化 特例: static const int period = 30;满足三个条件 */ }; double Account::interestRate = 0.015; int main() { //Account::interestRate = 0.015;错误,私有变量无法访问 //在未创建对象就可以对其修改,静态成员才可以怎么做 Account::rate(0.026); Account a("张三",1000); Account b("李四",2000); a.deposit(500); b.deposit(1000); cout << a.rate()<<endl;//0.015 //通过a修改,b进行查看 a.rate(0.018); cout << b.rate()<<endl;//0.018 Account::rate(0.02); a.applyint(); b.applyint(); cout << a.getAmount() << endl; cout << b.getAmount() << endl; return 0; }
