您的位置:首页 > 编程语言 > C语言/C++

C++面向对象笔记

2016-09-18 21:33 218 查看

类的定义

class obj {
int a;
string b;
void function(){
...;
}
};
obj x1;//实例化一个对象,于结构体类有多种实例化的方式。


也可以用结构体定义类

区别是class中的函数默认为private,结构体相反。

struct obj {
int a;
string b;
void function(){
...;
}
};
obj x1;


函数写到类外面,在类中声明即可。

public:
void play ();//声明函数
private:
string name;
int age;
};
void people :: play(){ //::意为play为people类中的函数
count<<"i am so happy !"<<endl;
};


内置函数inline

对于内置函数的处理,是将程序嵌入到调用点,并非正常的调用,所以执行效率很高。

由于调用函数的效率一般较低,而对于规模较小的函数一般采用内置的方式。

class people {
inline void eat();
void play (){//类中的函数默认为内置函数,不用声明。
...
}
};

inline void people::eat(){//类外函数如果是内置函数要声明。
...
}


对象实例化

class dog{
string name;
int age;
};
dog xiaoha = {"hashiqi",3};//实例化一只哈士奇


构造函数

构造函数自动执行且执行一次。

#include <iostream>
using namespace std;

class Time {
public:
Time(){     //构造成员函数
hour=0;
minute=0;
sec=0;
}
void set_time();
void show_time();
private:
int hour;
int minute;
int sec;
};

void Time::set_time(){
cin>>hour>>minute>>sec;
};
void Time::show_time(){
cout<<hour<<minute<<sec;
};

int main() {

Time t1;
t1.set_time();
t1.show_time();
return 0;
}


带参构造函数

#include <iostream>
using namespace std;

class Box{//类名首字母最好大写
public:
Box(int,int,int);//声明带参数的构造函数
int volume ();//声明计算体积的函数
private:
int height;
int width;
int length;
};

//实现构造函数以及成员函数
Box::Box(int h,int w,int l){
height = h;
width = w;
length = l;
}

int Box::volume(){

cout<< height*width*length;
}

int main() {

Box b1(12,13,14);
b1.volume();

return 0;
}


参数初始化列表对成员进行初始化

class People{
public:
People(int nu,int s,int na):num(s),sex(s),{strcpy(name,na);}
//通过:后面的列表将对应的属性初始化;
private:
int num;
char sex;
char name[20];
};
//实例化对象如下
People p1(01,'F',"Eric");


构造方法的重载

#include <iostream>
using namespace std;

class Box{//类名首字母最好大写
public:
Box ();
Box(int h,int w,int l):height(h),width(w),length(l){}//构造函数的重载
int volume ();//声明计算体积的函数
private:
int height;
int width;
int length;
};

int Box::volume(){

cout<< height*width*length;
}
int main() {

Box b1(12,13,15);
b1.volume();
return 0;
}


析构函数

是希望对象最后一次执行所要做的事

#include <iostream>
using namespace std;

class Box{//类名首字母最好大写
public:
Box ();
Box(int h,int w,int l):height(h),width(w),length(l){}//构造函数的重载
~Box(){ //析构函数
cout<<'\n'<<"啊。我马上要死了,析构函数要杀了我。";
}
int
4000
volume ();//声明计算体积的函数
private:
int height;
int width;
int length;
};

int Box::volume(){

cout<< height*width*length;
}
int main() {

Box b1(12,13,15);
b1.volume();
return 0;
}


输出结果:

2340

啊。我马上要死了,析构函数要杀了我。

对于有多个实例对象,先构造后构析。

对象数组

//类如下
class Box{
public :
Box(int w ,int h,int l):weight(w),height(h),length(l){}
int weight;
int height;
int lenght;
}

//定义一个类对象
Box box[3]={
Box(12,21,45),
Box(22,21,45),
Box(56,21,45),
};


指向函数的指针

//
int (*p)()//定义指向int 类型的函数指针

p = fun;//指针函数指向返回类型为int的fun函数

(*p)();//相当于fun函数的使用。


指向对象成员函数的指针

//类如下
class Box{
public :
Box(int w ,int h,int l):weight(w),height(h),length(l){}
int jisuan(){
...
}
private:
int weight;
int height;
int lenght;
}

//定义指向类成员函数的指针
int (Box::*p)();

//使指针指向类成员对象
p = &Box::jisuan;

//指向类成员函数指针的使用
(b1.*p)();//假定b1是一个对象


常对象

//使用上面的Box类
const Box b1(12,16,18);
Box const b1(12,16,18);//两者等价


常对象成员(属相)

//比如Box的一个成员为常对象成员,如下:
const int height;


常对象成员的值只能由初始化表对常对象成员进行初始化。

常成员函数

int jisuan()const;//注意格式,const是放在最后面的。


常指针相关总结

无论是常量还是常对象还是常指针的各种乱指。const靠近谁就是通过指针不能修改的。不通过指针不受影响。

对象的复制

Box box2(box1);//box2为复制的。


静态数据成员

class Box{
static int weight; //定义高为静态类型。
int height;
int lenght;
}

//静态类型初始化只能通过如下方式在类外初始化
int Box::height = 10; //不能通过构造函数以及参数列表进行修改。


静态数据成员既可以通过对象引用也可以通过类引用

class Box{
public:
static int weight; //定义高为静态类型。
int height;
int lenght;
}

Box b1;//实例化一个对象
//注意共有的前提
cout << b1.weight<< Box::weight<< endl;//静态数据成员的两种调用方法


静态成员函数

用法与静态成员变量类似

静态成员函数中可以访问静态成员变量,不能访问非静态成员变量。

class Box{
public:
static int weight; //定义高为静态类型。
int height;
int lenght;
static  int jisuan();//声明静态成员函数
}

//定义静态成员函数
int Box :: jisuan(){
cout<< weight<<endl;//合法;weight为静态
cout<< height<<endl;//非法;height非静态
}


定义对象数组并调用

//使用上面的类
Box box[]={
b1;
b2;
b3;
};
box[1].height ; //相当于b2.height


友元函数

友元普通函数

# include <iostream>
#include <string>//visual studio 运行要加这个头文件
using namespace std;
class Dog {
public:
Dog(string n,char s):name(n),sex(s){}
friend void show( Dog&);//声明友元函数,可以调用私有属性
string name;
private:
char sex;
};

//普通函数的实现
void show (Dog& d){
cout<<d.sex;//可以输出对象的私有属性
}

int main(){
Dog d1("heibao",'F');
show(d1);
//cout<<d1.name<<endl;
cout<<d1.name<<endl;
return 0;
}


友元成员函数

//Time 的类成员函数作为Date的友元函数既可以访问自己的私有属性,也可以访问Date的私有属性

# include <iostream>
#include <string>
using namespace std;

class Date;
class Time{
public:
Time(int h,int m, int s):hour(h),min(m),sec(s){}
void display(Date &);  //Time 的类成员函数作为Date的友元函数既可以访问自己的私有属性,也可以访问Date的私有属性。
private:
int hour;
int min;
int sec;
};

class Date{
public:
Date(int y,int m,int d):year(y),month(m),day(d){}
friend void Time::display(Date &);
private:
int year;
int month;
int day;
};

void Time::display(Date &d){
cout<<d.year<<d.month<<d.day;
cout<<'\\'<<hour<<min<<sec;
}
int main(){
Time t1(14,38,14);
Date d1(2016,9,23);
t1.display(d1);
return 0;
}


类模板

# include <iostream>

using namespace std;

//类模板使用
template <class numtype> //声明类模板中的可变数据类型为numtype

class Compare{
public:
Compare(numtype a,numtype b):ff(a),jj(b){}
void  max(){
cout<< ( (ff>jj) ? ff:jj);

}
void   min(){
cout<< (ff<jj ? ff:jj);
}
private:
numtype ff;
numtype jj;
};

int main(){
Compare <int> c1(12,23);
c1.max();
c1.min();
Compare <char> c2('a','b');
c2.max();
c2.min();
return 0;
}


派生类(继承)

class student :public people{ //student继承自people
...
};


继承方式总结

所有的public\private\protect继承方式都针对基类的public属性,以为将基类的public属性变成派生类的(public\private\protect)类成员。对于protect比较特殊,当为公用派生继承和保护派生继承时,对于派生类基类的公用成员或保护成员都变为派生类的保护成员。

实例化的对象也是类外部。私有成员和保护成员只能被成员函数引用不能被实例化对象引用。

派生类构造函数与构析函数

由于基类的构造函数是不能被继承的,所以在初始化派生类的时候也要想办法将基类初始化,解决办法是在初始化基类的时候调用基类构造函数。

//简单派生类的构造与构析函数
#include <iostream>
using namespace std;

class People {
public :
People(string n, char s):name(n),sex(s){}
~People(){}
private:
string name;
char   sex;
};

class Eric :public People{
public :
Eric(string n, char s,string l ):lover(l),People(n,s){}//这就是派生类的构造函数,注意格式。
void show (){
cout << lover;
}
private:
string lover;
};
int main() {
Eric eric1("sun",'f',"aini");
eric1.show();
return 0;
}
//输出结果anni


执行顺序:先调用基类构造函数再派生类构造函数

先派生类析构函数再基类构析函数。

//有子对象的派生类构造函数
//对上面的Eric类增加master,master也是People类,所以注意格式啊
class Eric :public People{
public :
Eric(string n, char s, string n1, char s1,string l ):lover(l),People(n,s),master(n1,s1){}//这就是派生类的构造函数,注意格式。
private:
string lover;
People master;
};


//多级派生的构造函数
//假定EricSon 是Eric的派生类
class EricSon {
Public:
EricSon(string n, char s, string n1, char s1,string l,string z):zhiliang(z):Eric(n,s,n1,s1,l)
//这么一长串语句,希望以后不要看晕。
prvate:
string zhiliang;

};


多重继承

//============================================================================
// Name 多重继承       : NOPAIN.cpp
// Author      : eric
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
//
//
//
#include <iostream>
using namespace std;

class People {
public :
People(string n, char s):name(n),sex(s){}
~People(){}
private:
string name;
char   sex;
};
class Man{
public:
Man(int w):weight(w){}
void showWeight(){
cout<<weight;
}
private:
int weight;
};

//Eric是一个多重继承的派生类
class Eric : public People,public Man {//多重继承,本类的重构就按标准来放最后吧
public :
Eric(string n, char s,int w,string l ):People(n,s),Man(w),lover(l){}
void show (){
cout << lover;
}
private:
string lover;
};
int main() {
Eric  eric1("sun",'f',76,"aini");
eric1.show();
return 0;
}


多重继承引起的二义性

//下面函数的继承关系
//AB继承X,C多重继承AB
#include <iostream>
using namespace std;
class X {
public:
int a;
X(int x=1){a=x;}
void display (){
cout<<X::a;
}
};

class A: public X {
public :
int a;
A(int x=2){a=x;}
void display(){
cout << A::a;
}
};

class B: public X {
public :
int a;
B(int x=3){a=x;}
void display(){
cout << B::a;
}
};

class C :public A ,public B {
public :
int a;
C(int x=4){a=x;}
void display(){
cout << C::a;
}
};

int main() {
C c1;
c1.A::display();
c1.B::display();
c1.C::display(); //这个和下面等同
c1.display();
return 0;
}


虚基类

在多重继承中,如果继承的父类有共同的父类则会出现二义性,会出现第三层的派生类在调用父类继承的成员属性的时候需要限定成员属性的域,如下示例

c1.A::display();
c1.B::display();


虚基类就是为了避免二义性出现的,具体如下代码所示:

//谨以此段代码献给我家的老狗黑豹,想你;
# include <iostream>
#include <string>
using namespace std;

class Dog {
public:
Dog(string n,int a):name(n),age(a){}
string name;
int age;
};
class WatchDog:virtual public Dog{ //虚基类是在这块体现的
public:
WatchDog(string n,int a,string ad):Dog(n,a),address(ad){}
string address;
};
class PetDog : virtual public Dog{
public:
PetDog(string n , int a ,string h):Dog(n,a),host(h){}
string host;
};

//多重继承
class MiniDog:public WatchDog ,public PetDog {
public:
MiniDog (string n ,int a,string ad,string h,int w):Dog(n,a),WatchDog(n,a,ad),PetDog(n,a,h),weight(w){}
int weight;
};
int main(){
MiniDog mydog("heibao",5,"oldYeard","MyFmally",40);
cout <<mydog.name<<"我下次回家一定来看你";
return 0;
}


指向基类的指针函数可以指向派生类。(相反则不行)

多态性:向不同的对象发送同一个消息,不同的对象接收到相同的消息后做出不同的行为。

重载运算符

成员函数来重载运算符

#include  <iostream>
using namespace std;
class X{
int i;
public:
X(int n=0){i=n;}  //构造函数初始化

X operator   +(const X &rx){  //运算符重载函数
i+=rx.i +3;
return X(i);
}

int GetI(){return i;}  //GET函数返回对象的成员属性
};

int main(){
X a(1),b(3);
cout<<(a+b).GetI()<<endl;   //重点:a+b 相当于 a.operate + (b);
return 0;
}


用友元函数来重载运算符

#include  <iostream>
using namespace std;
class Complex{
public:
Complex(double r=0.0,double i=0.0){  //构造并初始化
real=r;
image=i;
}
friend Complex operator+(const Complex&,const Complex&);
void display();
private:
double real;
double image;
};

Complex operator+(const Complex &c1,const Complex &c2){
return Complex(c1.real+c2.real,c1.image+c2.image);
}

void Complex::display(){
cout<<"("<<real<<","<<image<<"i)"<<endl;
}

int main(){
Complex c1(3,4),c2(5,-10),c3;
c3=c1+c2;
cout<<"c1=";c1.display();
cout<<"c2=";c2.display();
cout<<"c1+c2=";c3.display();
return 0;
}


静态联遍与动态联遍

静态联遍

#include <iostream>
using namespace std;
class Rectangle
{
public:
//构造函数
Rectangle(double a,double b){h=a;w=b;}
double area(){return h*w;}
private:
double h,w;
};
class Circle:public Rectangle
{
public:
//构造函数
Circle(double a,double b,double c):Rectangle(a,b){r=c;}
double area(){return 3.14*r*r;}
private:
double r;
};
void func(Rectangle &rec)
{
cout<<rec.area()<<endl;
}
void main()
{
Rectangle r1(2,3);
Circle c1(4,5,1);
func(r1);
func(c1);//讲道理,应该输出3.14,但因为静态联遍,在编译后就决定要使用父类的函数
}


动态联遍,要解决上面的问题就使用动态联遍,将area函数声明为虚函数,如下代码所示:

#include <iostream>
using namespace std;
class Rectangle
{
public:
//构造函数
Rectangle(double a,double b){h=a;w=b;}
virtual double area(){return h*w;}
private:
double h,w;
};
class Circle:public Rectangle
{
public:
//构造函数
Circle(double a,double b,double c):Rectangle(a,b){r=c;}
virtual double area(){return 3.14*r*r;}
private:
double r;
};
void func(Rectangle &rec)
{
cout<<rrec.area()<<endl;
}
void main()
{
Rectangle r1(2,3);
Circle c1(4,5,1);
func(r1);
func(c1);
}


纯虚函数

就是不用再父类中实现的函数,声明方法较一般的虚函数多了=0

class Dog  {
virtual void bark () = 0;
}


抽象类

包含纯虚函数的类就叫做抽象类。

抽象类不能派生新类

简易异常处理

出现异常时一般是抛给调用者处理。如下计算面积的函数如果throw a,则会在主函数里面的try里面处理,正好catch的类型是double,所以会劫持住问题‘’

# include <iostream>
# include <cmath>
using namespace std;
int main(){
double triangle (double ,double ,double);//函数声明
double a,b,c;
cin >>a>>b>>c;

try{
while (!(a<0||b<0||c<0)){
cout<<triangle(a,b,c);
cin>>a>>b>>c;
}

}
catch(double ) {
cout<<"不能构成三角形";
}
return 0;
}

double triangle (double x ,double y ,double z){
double s = (x +y+z)/2;
if(x+y<z||x+z<y||z+y<x)  throw x;
return sqrt(s*(s-x)*(s-y)*(s-z));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: