wap门户网站源码,网页设计与制作论文800字,开源建站软件,网站前置审批怎么做C面向对象程序设计-北京大学-郭炜【课程笔记#xff08;七#xff09;】 1、类型转换运算符2、自增、自减运算符的重载3、继承和派生的基本概念3.1、基本概念3.2、派生类对象的内存空间 4、继承关系和复合关系4.1、继承关系的使用4.2、复合关系的使用 5、派生类覆盖基类成员6… C面向对象程序设计-北京大学-郭炜【课程笔记七】 1、类型转换运算符2、自增、自减运算符的重载3、继承和派生的基本概念3.1、基本概念3.2、派生类对象的内存空间 4、继承关系和复合关系4.1、继承关系的使用4.2、复合关系的使用 5、派生类覆盖基类成员6、存储权限说明符protected7、派生类的构造函数8、public继承的赋值兼容规则9、直接基类与间接基类套娃 毕业中学习速度较慢 开始课程P21 6_6. 类型转换运算符的重载 课程链接程序设计与算法三C面向对象程序设计 北京大学 郭炜 课程PPTgithub提供的对应课程PPT
1、类型转换运算符 重载强制类型转换符 double 形式operator double () {return real}; 类型转换符重载是不需要写返回值类型的默认其double自身。 案例解释包含在代码中
#include iostream
using namespace std;class Complex
{double real, imag;public:Complex(double r0, double i0):real(r), imag(i) {};operator double () {return real;}// 重载强制类型转换运算符 double返回类型就是double不用单独写出
};int main()
{Complex c(1.2, 3.4);cout (double)c endl; // 输出1.2 //等价于c.operator double()double n 2 c; // 等价于double n 2c.operator double()// 本来2和c是不能相加的因为2为一个整形数字c确实一个对象// 所以这里调用了重载类型转换运算符cout n; // 输出 3.2
}2、自增、自减运算符的重载 自增运算符、自检运算符–有前置/后置之分为了区分所有重载的是前置运算符还是后置运算符C规定 前置运算符作为一元运算符重载 重载为成员函数: T operator(); T operator–(); 重载为全局函数 T operator(T ); T operator—(T ); 使用样例obj, obj.operator(), operator(obj) 都调用上述函数 后置运算符作为二元运算符重载多写一个没用的参数即可这参数不具备任何意义也不会被使用 重载为成员函数: T operator(int); T operator–(int); 重载为全局函数: T operator(T , int); T operator–(T , int); 使用样例obj, obj.operator(0), operator(obj,0) 都调用上函数
注意事项在vs中obj也调用前置重载而dev则令obj编译出错。
案例课程中的所有解释均在代码中呈现请配合课程看代码
#includeiostream
using namespace std;class CDemo
{private:int n;public:CDemo(int i0):n(i) {}CDemo operator(); // 用于前置形式返回值为引用CDemo operator(int); // 用于后置形式返回值为对象// 后置类型的为什么没使用引用呢// 答在C中 aa的返回值就是a的引用所以在重载前置运算符时我们需要尽量维持它原本的属性。 operator int() {return n;} // 类型强制转换运算符直接可以cout输出对象friend CDemo operator--(CDemo ); // 全局前置friend CDemo operator--(CDemo , int); // 全局后置
};CDemo CDemo::operator() // 返回值为CDemo对象的引用
{// 前置 n;return * this; // 返回值是一个对象即对* this的引用
} // s即为s.operator()即返回值就是s的引用 sCDemo CDemo::operator(int k) // 这里的k是无用的参数 返回值为CDemo对象
{// 后置 CDemo tmp(*this); // 记录修改前的对象n;return tmp; // 返回修改前的对象
} // s即为s.operator(0);CDemo operator--(CDemo d) // 这里的引用可不是只为了节省空间而是要通过该引用更改成员变量
{// 前置--d.n--;return d; // 返回对操作数的引用即d的引用
} // --s即为operator--(s)CDemo operator--(CDemo d, int)
{// 后置--CDemo tmp(d); // 生成一个临时的对象因为后置本身输出的值大小不变但其运行完后该对象中的--或才生效所以返回的对象是其自身。d.n--;return tmp; // 返回操作数的对象即d
} // s--即为operator--(s, 0)int main()
{CDemo d(5);cout (d) ,; //等价于 d.operator(0); //重载为成员函数的形式cout d ,; // 可以重载左移运算符或者重载一个强制类型转换运算符即可输出dcout (d) ,; //等价于 d.operator(); //重载为成员函数的形式cout d endl;cout (d--) ,; //等价于 operator--(d,0); //重载为全局函数的形式cout d ,;cout (--d) ,; //等价于 operator--(d); //重载为全局函数的形式cout d endl;return 0;
}// OUT
MacBook-Air beida_lesson % g 21.cpp -o 21
MacBook-Air beida_lesson % ./21
5,6,7,7
7,6,5,5注意事项一共有以下一些观点 由上述代码可知后置运算符的重载比前置运算符的重载多了一个临时函数的构建所以前置运算符在时间上的开销要小于后置运算符重载的开销特别是遇到递归时变得就比较明显了。所以提倡写前置运算符。 3、继承和派生的基本概念
3.1、基本概念 继承在定义一个新的类B时如果该类与某个已有的类A相似指的是B拥有A的全部特点那么就可以把A作为一个基类而把B作为基类的一个派生类也称子类。派生类是通过对基类进行修改和扩充得到的。在派生类中可以扩充新的成员变量和成员函数。派生类一经定义后可以独立使用不依赖于基类。派生类拥有基类的全部成员函数和成员变量不论是private、protected、public。 在派生类的各个成员函数中不能访问基类中的private成员。 案例 所有学生都有的共同属性 姓名 学号 性别 成绩 所有学生都有的共同方法成员函数 是否该留级 是否该奖励 不同学生又有个字各自不同的属性和方法 研究生 导师 系 大学生 系 中学生 竞赛特长加分 class CStudent
{private:string sName;int nAge;public:bool IsThreeGood() {};void SetName(const string name){sName name;}
};// 要毕业的学生
class CUndergraduateStudent: public Cstudent
{private:int nDepartment; // 添加自己的新的成员变量public:bool IsThreeGood() {.....}; // 覆盖与基类的成员函数名一样但内容不一样bool CanBao Yan() {.....};
}; // 派生类的写法是类名public基类名// 研究生
class CGraduatedStudent:public CStudent
{private:int nDepartment;char szMentorName[20];public:int CountSalary() {.....};
}3.2、派生类对象的内存空间 派生类对象的体积等于基类对象的体积再加上派生类对象自己的成员变量的体积。在派生类对象中包含着基类对象而且基类对象的春初位置位于派生类对象新增的成员变量之前。 举例一个完整的例子两个类的简单学生管理程序
// File name22.cpp
#includeiostream
#includestring
using namespace std;class CStudent
{private:string name;string id; // 学号char gender; // 性别 “F”代表女 “M”代表男int age;public:void PrintInfo();void SetInfo(const string name_, const string id_, int age_, char gender_);string GetName() {return name;}
};void CStudent::PrintInfo()
{cout Name name endl;cout ID id endl;cout Age age endl;cout Gender gender endl;
}void CStudent::SetInfo(const string name_, const string id_,int age_, char gender_)
{name name_;id id_;age age_;gender gender_;
}class CUndergraduateStudent:public CStudent
{// 本科生类继承了CStudent类private:string department; // 学生所属的系的名称public:void QualifiedForBaoyan(){// 输出给予保研资格cout qualified for baoyan endl;}void Printfo() // 覆盖CUndergraduateStudent自己的Printfo{CStudent::PrintInfo(); // 调用基类PrintInfocout Department: department endl;}void SetInfo(const string name_, const string id_, int age_, char gender_, const string department_){CStudent::SetInfo(name_, id_, age_, gender_); // 调用基类的Setinfodepartment department_;}
};int main()
{CUndergraduateStudent s2;s2.SetInfo(Harry Potter, 118829212, 19, M, Computer Science);cout s2.GetName() ;s2.QualifiedForBaoyan();s2.PrintInfo();return 0;
}// OUT
MacBook-Air beida_lesson % g 22.cpp -o 22
MacBook-Air beida_lesson % ./22
Harry Potterqualified for baoyan
Name Harry Potter
ID 118829212
Age 19
Gender M4、继承关系和复合关系 继承关系“是” 关系 基类AB是基类A的派生类。逻辑上要求“一个B对象也是一个A对象”。例从学生类派生出中学生类因为中学生也是学生。 复合关系“有”关系。 类C中“有”成员变量kk是类D的对象则C和D是复合关系一般逻辑上要求“D对象是C对象的固有属性或组成部分”。 4.1、继承关系的使用 4.2、复合关系的使用 5、派生类覆盖基类成员
派生类可以定义一个和基类成员同名的成员这叫覆盖。在派生类中访问这类成员时缺省的情况是访问派生类中定义的成员。要在派生类中访问有基类定义的同名成员时要使用作用域符号::。 class base
{int j;public:int i;void func();
};class derived : public base
{public:int i;void access();void func();
};void derived::access()
{// j 5; // error,这是base的私有成员变量派生类derived不能访问i 5; // 引用的是派生类的ibase::i 5; // 引用的基类的ifunc(); // 派生类的base::func(); // 基类的}int main()
{derived obj;obj.i 1; // 派生类的iobj.base::i 1; // 引用的基类的i
}// 在派生类和基类中不要写相同的成员变量如上代码中的i注意事项在派生类和基类中不要写相同的成员变量如上代码中的i 6、存储权限说明符protected 特点基类的protected成员可以被以下函数访问
基类的成员函数基类的有缘函数派生类的成员函数可以访问当前对象的基类的保护成员
class People
{private: int nPrivate; // 私有成员public: int nPublic; // 公有成员protected: int nProtected; // 保护成员
};class Son:public People
{void Accesspeople(){nPublic 1; // OknPrivate 1; // wrongnProtected 1; // Ok, 访问从基类继承的protected成员Son f; // 非当前对象 f.nProtected 1; // wrong, f 不是当前对象}
};int main()
{People f; Son s;f.nPublic 1;s.nPublic 1;f.nProtected 1; f.nPrivate 1; s.nProtected 1; s.nPrivate 1;
}7、派生类的构造函数 class Bug
{private:int nLegs;int nColor;public:int nType;Bug(int nLegs_, int nColor_);void PrintBug(){};
};class FlyBug:public Bug // FlyBug是Bug的派生类
{int nWings;public:FlyBug(int nLegs_, int nColor_, int nWings_);
};Bug::Bug(int legs, int color)
{nLegs legs;nColor color;
}// 错误的FlyBug构造函数
FlyBug::FlyBug(int legs, int color, int wings)
{nLegs legs; // 不能访问nColor color; // 不能访问nType 1; // OK基类的公有成员没有问题的nWings wings;
}// 正确的FlyBug构造函数
// 直接初始化派生类所包含的基类的Bug对象即Bug构造函数初始化列表
FlyBug::FlyBug(int legs, int color, int wings):Bug(legs, color) // 基类的构造函数
{nWings wings;
}int main()
{FlyBug fb(2, 3, 4); // 调用构造函数初始化fb.PrintBug();fb.nType 1;fb.nLegs 2; // error , nLegs is privatereturn 0;
}例
#include iostreamclass Base
{public:int n;Base(int i):n(i){std::cout Base n constructed std::endl;}~Base(){std::cout Base n destructed std::endl;}
};class Derived:public Base
{public:Derived(int i):Base(i) // 1、先进入Base构造函数{ std::cout Derived constructed std::endl;} //2、进入Drivate构造函数~Derived(){std::cout Derived destructed std::endl;}
};int main()
{Derived Obj(3);return 0;// 3、执行 Derived析构函数// 4、执行 Base析构函数
}// OUT
MacBook-Air beida_lesson % ./23
Base3 constructed
Derived constructed
Derived destructed
Base 3destructed例题2:
#include iostreamclass Bug
{private:int nLefs; int nColor;public:int nType;Bug(int legs, int color);void PrintBug() {};
};class Skill
{public:Skill(int n) {};
};class nWings
{public:nWings(int nWings_) {};
};class FlyBug:public Bug
{nWings w1;Skill sk1, sk2;public:FlyBug(int legs, int color, int wings);
};FlyBug::FlyBug(int legs, int color, int wings):Bug(legs, color), sk1(5), sk2(2), w1(wings) {}老师版本
#include iostreamclass Bug
{private:int nLefs; int nColor;public:int nType;Bug(int legs, int color);void PrintBug() {};
};class Skill
{public:Skill(int n) {};
};class FlyBug:public Bug
{int nWings;Skill sk1, sk2;public:FlyBug(int legs, int color, int wings);// nWings(int nWings_) { nWings nWings_};
};FlyBug::FlyBug(int legs, int color, int wings):Bug(legs, color), sk1(5), sk2(2), nWings(wings) {}8、public继承的赋值兼容规则 以下等号“”并没有采用运算符重载。 9、直接基类与间接基类套娃 例
#include iostreamclass Base
{public:int n;Base(int i):n(i){std::cout Base n constructed std::endl;}~Base(){std::cout Base n destructed std::endl;}
};class Derived:public Base
{public:Derived(int i):Base(i){ std::cout Derived constructed std::endl;}~Derived(){std::cout Derived destructed std::endl;}
};class MoreDerived:public Derived
{public:MoreDerived():Derived(4){std::cout More Derived constructed std::endl;}~MoreDerived(){std::cout More Derived destructed std::endl;}
};int main()
{MoreDerived Obj;return 0;
}// OUT~MoreDerived()^
2 errors generated.
MacBook-Air beida_lesson % g 23.cpp -o 23
MacBook-Air beida_lesson % ./23
Base4 constructed
Derived constructed
More Derived construct