#include<iostream> using namespace std; class A; class B{ public: void f(A* pt){}; } class A{ public: void f(B *pt){} } 第3行声明了A类,A类的定义在后面,之所以要提前声明,是因为B类的定义中用到了A类型(第6行),而此时A类还没有定义,编译会报错.不要第三行,而把A类的定义写在B类前面,是解决不了这个问题的,因为A类中也用到了B类(第10行),把A类的定义写在前面会导致第1…
假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是一种直观的写法: #include<iostream> using namespace std; class CDog; class CMaster { CDog dogs[10]; int dog_num; }; class CDog { CMaster m; }; int main() { }…
“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespace std; class A{ public: int i; virtual void func(){}; virtual void func2(){}; //如果为只有一个去掉 virtual 关键字即virtual void func2(){};变为 void func2(){}; 输出结果不变 仍为 8…
  封闭类:  一个类的成员变量如果是另一个类的对象,就称之为“成员对象”.包含成员对象的类叫封闭类. #include<iostream> using namespace std; class A{ int n; public: A(int n):n(n){} }; class B{ A t; int g; public: B(int n,int g):t(n),g(g){} }; B是一个封闭类,生成封闭类对象的语句一定要让编译器能够弄明白其成员对象的是如何初始化的,否则就会编译错误. 封…
定义: string类是STL中basic_string模板实例化得到的模板类.其定义如下: typedef basic_string<char>string; 构造函数: string类有多个构造函数,但没有接收一个整型参数或一个字符型参数的构造函数 string s1(); //s1="" string s2("hello"); //s2="hello" string s3(4,'k'); //s3="kkkk"…
在c++中,类和类之间有两种基本关系:复合关系和继承关系. 复合关系也称为“has a”关系或“有”的关系,表现为封闭类,即一个类以另一个类的对象作为成员变量. 继承关系也称为“is a”关系或“是”关系,即派生类对象也是一个基类对象. 在设计两个有关系的类时要注意,并非两个类有共同点,就可以让它们成为继承关系.让类B继承类A,必须满足“类B所代表的事物也是类A所代表的事物”这个命题从逻辑上是成立的.例如:写一个平面上的点类point: class CPoint{ double x,y; };…
类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespace std; class CBase { public: void func1() { func2(); } virtual void func2(){cout<<"CBase::func2()"<<endl;} }; class CDerived:public…
游戏软件的开发最能体现面向对象设计方法的优势.游戏中的人物.道具.建筑物.场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程.每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方法,特别适合使用继承.多态等面向对象的机制.下面就以“魔法门”游戏为例来说明多态在增加程序可扩展性方面的作用. “魔法门”游戏中有各种各样的怪物,如骑士.天使.狼.鬼,等等.每个怪物都有生命力.攻击力这两种属性.怪物能够相互攻击.一个怪物攻击另一个怪物时,被攻击者会受伤:同时被攻击者会反击,使得攻击…
1.当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用.例如,下面的两条语句都会引发复制构造函数的调用,用以初始化c2. C c2 (c1); C c2=c1; 这两条语句是等价的.注意第二条是初始化语句,不是赋值语句.赋值语句的等号左边是一个早已有定义的变量,赋值语句不会引发复制构造函数的调用.例如: C c1,c2; c1=c2; "c1=c2;"这条语句不会引发复制构造函数的调用,因为c1早已生成,已经初始化过了. 2.如果函数F的参数是类C的对象,那么当F被调用时…
示例1: #include<iostream> using namespace std; class CDemo{ public: ~CDemo(){cout<<"destructor"<<endl;} }; void Func(CDemo obj){ cout<<"func"<<endl; } CDemo d1; CDemo Test(){ cout<<"test"<…
背景:   c++是在c语言的基础上发展而来的,第一个c++的编译器实际上是将c++程序翻译成c语言程序,然后再用c语言编译器进行编译.c语言没有类的概念,只有结构,函数都是全局函数,没有成员函数.翻译时,将class翻译成struct.对象翻译成结构变量是显而易见的,但是对类的成员函数应该如何翻译?对“my.modify();”这样通过一个对象调用成员函数的语句,又该如何翻译呢? c语言只有全局函数,因此成员函数只能被翻译成全局函数:“my.modify();”这样的语句也只能翻译成普通的调用…
背景: 数组的长度是定义好的,在整个程序中固定不变.c++不允许定义元素个数不确定的数组.例如: int n; int a[n]; //这种定义是不允许的 但是在实际编程中,往往会出现要处理的数据数量在编程时无法确定的情况.如果总是定义一个尽可能大的数组,又会造成空间浪费.何况,这个“尽可能大”到底应该多大才够呢? 为了解决这个问题,c++提供了一种“动态分配内存”的机制,使得程序可以在运行期间,根据实际需要,要求操作系统临时分配一片内存空间用于存放数据.这种内存分配是在程序运行中进行的,而不是…
背景: 使用函数能够避免将相同代码重些多次的烦恼,还能减少可执行程序的体积,但也会带来程序运行时间上的开销.函数调用在执行时,首先在栈中为形参和局部变量分配存储空间,然后还要将实参的值复制给形参,接下来还要将函数的返回地址(改地址指明了函数执行结束后,程序应该回到哪里继续执行)放入栈中,最后才跳转到函数内部执行.这个过程是要耗费时间的.另外,函数执行return语句返回时,需要从栈中回收形参和局部变量占用的存储空间,然后从栈中取出返回地址,再跳转到该地址继续执行,这个过程也要耗费时间.总之,使用…
类型转换构造函数:  除复制构造函数外,只有一个参数的构造函数一般可以称作类型转换构造函数,因为这样的构造函数能起到类型自动转换的作用.例如下面的程序: #include<iostream> using namespace std; class Complex{ public: double real,imag; Complex(int i){ cout<<"IntConstructor called"<<endl; real=i;imag=0; }…
面向对象的程序设计方法 抽象:将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性):将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构. 封装:通过某种语法形式,将数据结构和操作该数据结构的函数“捆绑”在一起,形成一个“ 类”,从而使得数据结构和操作该数据结构的算法呈现出显而易见的紧密关系. 从客观事物抽象出类 写一个程序,输入矩形的长和宽,输出面积和周长. 比如对于“矩形”这种东西,要用一个类来表示,该如何做“抽象”呢?矩形的属…
1.结构化程序设计的不足 程序=算法+数据结构 数据结构和变量相对应,算法和函数相对应,算法是用来操作数据结构的. 结构化程序设计中,函数和其所操作的数据结构,没有直观的联系.随着程序规模的增加,程序逐渐难以理解,很难一下子看出来:某个数据结构到底有哪些函数可以对它进行操作?某个函数到底是用来操作哪些数据结构的?任何两个函数之间存在怎样的调用关系? 结构化程序设计没有"封装"和"隐藏"的概念. 要访问某个数据结构中的某个变量,就可以直接访问,那么当该变量的定义有改动…
简单继承的例子: #include <iostream> #include <string> 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…
形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { public: double real,imag; Complex( double r = 0.0, double i= 0.0 ):real(r),imag(i) { } Complex operator-(const Complex & c); }; Complex operator+( const C…
一.重载类型强制转换运算符 在C++中,类型的名字(包括类的名字)本身也是一种运算符,即类型强制转换运算符.类型强制转换运算符是单目运算符,也可以被重载,但只能重载为成员函数,不能重载为全局函数.经过适当重载后,“(类型名)对象”这个对对象进行类型强制转换的表达式就等价于“对象.operator类型名()”,即变成对运算符函数的调用. 下面的程序对double类型类型强制转换运算符进行了重载. #include <iostream> using namespace std; class Com…
实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back(i);//->要用动态分配的内存来存放数组元素,需要一个指针成员变量 CArray a2, a3; a2 = a;//->要重载“=” ; i < a.length(); ++i) cout << a2[i] << " ";//->要重载“[…
一.C++程序到C程序的翻译 程序示例分析: C++: class CCar { public: int price; void SetPrice (int p); }; void CCar::SetPrice (int p) { price = p; } int main() { CCar car; car.SetPrice(); ; } C: struct CCar { int price; }; void SetPrice(struct CCar * this,int p) { this-…
一.成员对象和封闭类 (1)定义 一个类的成员变量如果是另一个类的对象,就称之为“成员对象”. 包含成员对象的类叫封闭类. (2)封闭类构造函数的初始化列表 在构造函数中添加初始化列表的写法: 类名::构造函数名(参数表):成员变量1(参数表),成员变量2(参数表),··· { ··· } “:”和“{”之间的部分就是初始化列表.初始化列表中的成员变量既可以是成员对象,也可以是基本类型的成员变量. class CTyre //轮胎类 { private: int radius; //半径 int…
1.构造函数.析构函数和变量的生存期 构造函数在对象生成时会被调用,析构函数在对象消亡时会被调用. 程序示例分析: (1) #include<iostream> using namespace std; class Demo { int id; public: Demo(int i) { //类型构造函数 id = i; cout << "id=" << id << " constructed" << en…
构造函数 1.构造函数的概念和作用 (1)概念 构造函数就是一类特殊的成员函数,其名字和类一样,不写返回值类型(void也不可以写),可以有参数,可以重载. 如果定义类时没写构造函数,则编译器生成一个默认的无参的构造函数 ,默认构造函数无参数,不做任何操作.如果定义了构造函数,则编译器不生成默认的无参数的构造函数 注意: 一个类可以有多个构造函数. 对象生成时构造函数自动被调用.对象一旦生成,就再也不能在其上执行构造函数 . 程序示例分析: ①默认构造函数 class Complex { pri…
 1.对象的内存匹配 一般来说,在C++中,一个对象占用的内存空间大小等于其成员变量所占用的内存空间的大小之和.(对象只包含成员变量,不包含成员函数) 每个对象都有各自的存储空间.一个对象的某个成员变量被改变后,不会影响另一个对象. 2.类的成员变量和成员函数使用方法 ①对象名.成员名 ②指针->成员名 ③引用名.成员名 3.类成员的可访问范围 private:用来指定私有成员.只在该类的成员函数内部才能被访问. public:用来指定公有成员.在任何地方都可以被访问. protected:用来…
1.内联函数(inline关键字) eg.inline int Max(int a,int b) { if(a>b) return a; return b; } 当编译器处理调用内联函数的语句时,直接将整个函数体的代码插入调用语句处,但是会使最终可执行程序的体积增加.(这是以空间换时间) 2.函数的重载(使函数命名变得简单) (1)定义:一个或多个函数,名字相同,然而参数个数或类型不同 (2)编译器判断形式:根据函数调用语句中实参的个数和类型来判断 eg. int MAX(int a,int b…
在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函数.如果本类有该函数,调用的就是本类的函数:如果本类没有,调用的就是直接基类的函数:如果基类没有,调用的就是间接基类的函数,以此类推.例如: #include<iostream> using namespace std; class A { public: virtual void hello(){cout<<"A::hello()"<<endl;} virtual void…
重载流插入运算符和流提取运算符 流插入运算符:“<<” 流提取运算符:“>>” cout 是在 iostream 中定义的,ostream 类的对象. “<<” 能用在cout 上是因为,在iostream里对 “<<” 进行了重载. 怎么重载才能使得cout << 5; 和 cout << “this”都能成立? ostream & ostream::operator<<(int n) { …… //输出n的代码…
运算符重载为友元函数 一般情况下,将运算符重载为类的成员函数,是较好的选择. 但有时,重载为成员函数不能满足使用要求,重载为普通函数,又不能访问类的私有成员,所以需要将运算符重载为友元. class Complex { double real,imag; public: Complex( double r, double i):real(r),imag(i){ }; Complex operator+( double r ); }; Complex Complex::operator+( dou…
一.重载赋值运算符“=” 赋值运算符“=”要求左右两个操作数的类型是匹配的,或至少是兼容的.有时候希望赋值运算符两边的类型可以不匹配,比如,把一个int类型变量赋值给一个Complex对象,或把一个 char * 类型的字符串赋值给一个字符串对象,此时就需要重载赋值运算符“=”.C++规定,赋值运算符“=”只能重载为成员函数. 程序示例分析: #include<iostream> using namespace std; class String { private: char* str; p…