代码
建议
1.返回已经存在的数据,尽量用引用类型,减少拷贝。
2.函数前const表示返回的是常量,后const表示不会对类中方数据进行改变,当作只读函数就行。
3.函数传参的时候尽量传引用,如果没有对数据进行修改,就加个const。
4.this指向当前对象,有时候为了连续调用即点连点会使用,具体看基础类学习。
5.使用IO类为参数,由于IO类型不可拷贝,所以使用的是引用参数,返回的也是引用类型,保证输出的流对象是一个对象,即传进来是谁,返回的也是谁c++p270。
5.运算符重载问题,使用了IO流的都是IO类调用本类的数据或者函数,所以必须是友元函数,否则没有权限。
6.有其他构造函数了也要写默认构造函数,复合类或者嵌套类有时候编译器不能自动合成默认构造函数。
7.const成员函数可以改变mutable数据成员。
8.const对象只能调用const成员,但是const对象的数据不能改变,所以使用前后两个const进行函数重载。
9.委托构造函数,可以根据输入的不同调用不同的构造函数。
10.explicit防止构造函数的隐式转换,例如只给某成员函数传入string,函数参数类型是class,结果自动调用了相应的构造函数,将类型进行了转换。explicit函数只能直接初始化。
问题以及学习内容
1.类名和define 重名
友元,相当于谁被用,谁写friend
2.友元类分两个文件写
class A 是 class B 的友元类,即class A可以使用class B 中数据
在 A.h 中,先声明class B,
class B;
class A{
private:...
public:...
}
在B.h中
#include"A.h"
class B{
private:...
public:
friend class A
...
}
3.友元函数-非成员函数
class A{
public:
friend void show(A &);
private:
}
void show(A &a){
...
}
4.友元函数-成员函数
class A
该类中使用class B的数据
class B
class A{
public:
void show(B &);
private:
}
class B
class B{
public:
friend void A::show(B &);
}
void A::show(B &){};
代码内容
1.友元类
class A.h
#ifndef WINDOW_MGR
#define WINDOW_MGR
#include<iostream>
#include<vector>
//友元类
#include"Screen.h"
using namespace std;
class Screen;
class Window_mgr
{
private:
//默认情况下,一个Window_mgr包含一个全是‘*’的Screen
vector<Screen> screens{Screen(5,5,'*')};
public:
typedef vector<Screen>::size_type ScreenIndex;
//指定编号的Screen清空
void clear(ScreenIndex);
//输出屏幕
void show();
//增加屏幕
ScreenIndex addScreen(const Screen&);
};
#endif
class A.cpp
#include"Window_mgr.h"
//调用了非本类的函数
void Window_mgr::show(){
for(auto temp:screens)
temp.dispaly(cout);
}
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen &s){
screens.push_back(s);
//返回其编号
return screens.size()-1;
}
void Window_mgr::clear(ScreenIndex i){
Screen &s = screens[i];
cout<<"clear: "<<s.height<<" "<<s.width<<endl;
s.contents = string(s.height*s.width,' ');
}
class B.h
#ifndef SCREEN
#define SCREEN
#include<iostream>
#include<string>
#include"windows.h"
//#include"Window_mgr.h"
using namespace std;
//别名
typedef string::size_type pos;
class Screen
{
private:
//光标所在位置
pos cursor = 0,height = 0,width = 0;
//光标所在位置的字符
string contents;
mutable size_t access_ctr;
//输出函数
void do_display(ostream &os) const{
os<<contents;
}
public:
//声明友元类,即可以调用Screen类中的函数
friend class Window_mgr;
Screen() = default;
//给定屏幕的尺寸,声明一个一维数组,用于存放字符
Screen(pos ht,pos wd, char c):height(ht),width(wd),contents(ht*wd,c){};
//隐式内联,获取光标处的字符
char get() const{return contents[cursor];}
//显式内联,函数重载 获取给定处的字符
char get(pos ht,pos wd) const;
//之后设置为内联,移动光标
inline Screen &move(pos r,pos c);
//计数
void some_number() const;
//设置光标所在的字符
Screen &set(char);
//设置其他任意位置的字符
Screen &set(pos,pos,char);
//打印 非常量
Screen &dispaly(ostream &os);
//打印 常量
const Screen &display(ostream &os) const;
};
//r行 c列
//定义处设置内联,把光标移至指定位置
inline Screen& Screen::move(pos r,pos c){
pos row = r * width;
cursor = row + c;
//以左值的方式返回
return *this;
}
#endif
class B.cpp
#include"Screen.h"
//返回给定列的字符
char Screen::get(pos r,pos c) const{
pos row = r * width;
return contents[row+c];
}
void Screen::some_number() const{
++access_ctr;
}
Screen& Screen::set(char c){
contents[cursor] = c;
return *this;
}
Screen& Screen::set(pos r,pos col,char ch){
contents[r*width+col] = ch;
return *this;
}
Screen & Screen::dispaly(ostream &os){
do_display(os);
return *this;
}
const Screen& Screen::display(ostream &os) const{
do_display(os);return *this;
}
main.cpp使用
Screen myScreen(5,5,'x');
myScreen.move(4,0).set('#').dispaly(cout);
cout<<endl;
myScreen.dispaly(cout);
cout<<endl;
cout<<"Window"<<endl;
Window_mgr Screens;
int count = Screens.addScreen(myScreen);
Screens.show();
cout<<"myscreen number "<<count <<endl;
结果
2.基础类学习
class sales_data.h
#ifndef SALA_DATA
#define SALA_DATA
#include<iostream>
#include<string>
using namespace std;
class sales_data
{
private:
string bookno;//书号
double units_sold;//销售的册数
double price;
double revenue;//总销售额
double average;
public:
// 无参构造函数
sales_data();
//sales_data() = deflaut 默认构造函数;
//有参数的构造函数
sales_data(string b,int u,double p):bookno(b),units_sold(u),price(p){};
//运算符重载 友元函数,其他类调用该类中的私有数据,返回的是引用类型,必须保证是引用,否则调用构造函数,输入输出的对象不是一个,
friend istream& operator >> (istream &,sales_data &);
friend ostream& operator << (ostream &,sales_data &);
friend sales_data operator + (sales_data &lhs,sales_data & rhs);
//引用不会调用拷贝构造函数,在内存中不产生被返回值的副本
sales_data& operator = (const sales_data &);
friend bool operator == (sales_data &,sales_data &);
sales_data &operator += (const sales_data &);
double avg_price();
//声明isbn函数,返回书籍号
string isbn() const;
//一个combine成员函数,用于将一个sales_data对象加到另一个对象上
sales_data& combine(const sales_data &);
//声明sales_data类的非成员接口函数
//一个read函数,将数据从istream读入到sales_data对象中
friend istream & read(istream &,sales_data &);
//一个add函数,执行两个对象的加法
//friend sales_data add(const sales_data &, const sales_data &);
//sales_data add(const sales_data &, const sales_data &);
};
sales_data add(const sales_data &, const sales_data &);
#endif
class sales_data.cpp
#include"Sales_data.h"
// 加default 就不需要赋初始值
sales_data::sales_data(){
bookno = "null";
units_sold = 0;
price = 0.0;
}
//接下来的四个函数都是友元函数,其他类的,不需要加class的定义域
istream& operator >>(istream &input,sales_data &s){
input >> s.bookno >> s.units_sold >> s.price;
if(input){
s.revenue = s.units_sold * s.price;
}
return input;
}
ostream& operator << (ostream &output,sales_data &s){
output << s.bookno <<" "<< s.units_sold << " "<<s.revenue<<" "<<s.avg_price()<<endl;
return output;
}
//返回的是函数内部的变量,需要是拷贝值
sales_data operator + (sales_data &lhs,sales_data &rhs){
sales_data ret;
ret.bookno = lhs.bookno;
ret.units_sold = lhs.units_sold + rhs.units_sold;
ret.avg_price();
return ret;
}
bool operator == (sales_data &lhs,sales_data &rhs){
return lhs.units_sold == rhs.units_sold && lhs.price == rhs.price;
}
//重载赋值运算符 本类中声明的函数
sales_data& sales_data::operator = (const sales_data &lhs){
bookno = lhs.bookno;
units_sold = lhs.units_sold;
price = lhs.price;
return *this;
}
sales_data& sales_data::operator += (const sales_data &rhs){
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
double sales_data::avg_price(){
average = revenue / units_sold;
return average;
}
string sales_data::isbn() const{
return bookno;
}
//和重载的+一致,只要返回的不是该函数内部的都加引用
sales_data &sales_data::combine(const sales_data &rhs){
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
istream & read(istream &input,sales_data &rhs){
input >> rhs.bookno >> rhs.units_sold >> rhs.price;
rhs.revenue = rhs.units_sold * rhs.price;
return input;
}
sales_data add(const sales_data &lhs,const sales_data &rhs){
sales_data sum = lhs;
sum.combine(rhs);
sum.avg_price();
return sum;
}
3.静态成员与静态函数
student.h
#ifndef STUDENT
#define STUDEBT
#include<iostream>
using namespace std;
class Student{
public:
Student(int n,int a,float s):num(n),age(a),score(s){}
void total();
//声明静态成员函数,求取平均分,这写static,后面就不用写了
static float average();
private:
int num;
int age;
float score;
//计算总分
static float sum;
//统计人数
static int count;
};
#endif
student.cpp
#include"Student.h"
void Student::total(){
sum += score;
count++;
}
float Student::average(){
return (sum/count);
}
main.cpp
Student stu[3]={
Student(1001,18,70),
Student(1002,19,78),
Student(1005,20,98),
};
int n;
cout<<"how many students' grates? ";
cin>>n;
for(auto &it : stu){
it.total();
}
cout<<"average = "<<Student::average()<<endl;
结果