c++primer——面向对象编程
2015-10-15 20:11
465 查看
1.重构现象:因为派生类的构造函数只能初始化它的直接基类,所以这样就出现了一种新的现象——重构,重构是很常见的,它是指在子类中重新定义父类的构造函数,已达到自己想要的构造函数。重构要注意的是一旦被重构,编译器必须重新编译这些类的代码。
友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。友元关系不能传递和继承。
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
友元类的申明只对申明对象有效,对申明对象的基类和子类是无效的。友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。 当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名; 其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
突然想到之前的一个知识点:struct和class的唯一区别是类的成员的默认保护级别,在struct的默认是public,而class的默认情况下是private的。
3.虚函数和作用域
5.构造和析构的调用顺序:下例:
class base
{
public:
base()
{
cout<<"base_c"<<endl;
}
~base()
{
cout<<"base_d"<<endl;
}
virtual int fun(){return 0;};
};
class D1:public base
{
public:
D1()
{
cout<<"d1_c"<<endl;
}
~D1()
{
cout<<"d1_d"<<endl;
}
int fun(int ){return 0;};
virtual void f2(){};
};
class D2:public D1
{
public:
D2()
{
cout<<"d2_c"<<endl;
}
~D2()
{
cout<<"d2_d"<<endl;
}
int fun(int){return 0;};
int fun(){return 0;};
void f2(){};
};
int main()
{
base b1;
D1 d1;
D2 d2;
base *bp1=&b1,*bp2=&d1,*bp3=&d2;//转化成基类
bp1->fun();
bp2->fun();
bp3->fun();
D1 *dp1=&d1;
D2 *dp2=&d2;
dp1->f2();
dp2->f2();
return 0;
}
输出结果:
base_c
base_c
d1_c
base_c
d1_c
d2_c
d2_d
d1_d
base_d
d1_d
base_d
base_d
无论是多少级继承,构造函数总是先从基类开始,而析构函数就是先从本身开始到基类。
class pp { public: pp() { a=0; cout<<a; } pp(int x,int y,int z) { a=x,b=y,c=z; cout<<a<<b<<c; } void test1(int i); protected: int a; int b; int c; }; class aa :public pp { public: aa(){} aa(int x,int y,int z):pp(x,y,z)//调用基类的哪个构造函数 { { a=x,b=y,c=2*z;//重构现象(一定是先调用基类的构造函数,然后在自己重构自己的函数) int d=a+b+c; cout<<d; } } };2.友元和继承
友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。友元关系不能传递和继承。
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 函数名(形式参数);
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元函数的调用与一般函数的调用方式和原理一致。
友元类的申明只对申明对象有效,对申明对象的基类和子类是无效的。友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。 当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名; 其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
突然想到之前的一个知识点:struct和class的唯一区别是类的成员的默认保护级别,在struct的默认是public,而class的默认情况下是private的。
3.虚函数和作用域
<span style="font-family:微软雅黑;">class base { public: virtual int fun(); }; class D1:public base { public: int fun(int );//这个并没有覆盖原来的fun() virtual void f2(); }; class D2:public D1 { public: int fun(int); int fun(); void f2(); }; /*</span><span style="font-family: 微软雅黑;">*/</span>
<span style="font-family:微软雅黑;"> int main() { base b1; D1 d1; D2 d2; base *bp1=&b1,*bp2=&d1,*bp3=&d2;//转化成基类 bp1->fun();//base::fun() bp2->fun();//base::fun() bp3->fun();//d2::fun() D1 *dp1=&d1; D2 *dp2=&d2; bp2->f2();//错误:base中没有f2的成员 dp1->f2();//d1::f2() dp2->f2();//d2::f2() return 0; }</span>4.虚析构函数:(一般基类的析构函数需要用虚函数)下例:
<pre name="code" class="cpp">class ClxBase { public: ClxBase() {}; virtual ~ClxBase() {}; virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; class ClxDerived : public ClxBase { public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }; };
<span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: rgb(230, 230, 230);">主函数:</span><pre name="code" class="cpp">ClxBase *pTest = new ClxDerived;//定义的是基类,这个跟基类是否是虚函数有很大关系
<pre name="code" class="cpp">ClxDerived *p=new <span style="font-family: Arial;">ClxDerived;//定义是派生类</span>pTest->DoSomething();delete pTest;
delete p;//无论基类是否是虚函数都会从派生类开始调用
5.构造和析构的调用顺序:下例:
class base
{
public:
base()
{
cout<<"base_c"<<endl;
}
~base()
{
cout<<"base_d"<<endl;
}
virtual int fun(){return 0;};
};
class D1:public base
{
public:
D1()
{
cout<<"d1_c"<<endl;
}
~D1()
{
cout<<"d1_d"<<endl;
}
int fun(int ){return 0;};
virtual void f2(){};
};
class D2:public D1
{
public:
D2()
{
cout<<"d2_c"<<endl;
}
~D2()
{
cout<<"d2_d"<<endl;
}
int fun(int){return 0;};
int fun(){return 0;};
void f2(){};
};
int main()
{
base b1;
D1 d1;
D2 d2;
base *bp1=&b1,*bp2=&d1,*bp3=&d2;//转化成基类
bp1->fun();
bp2->fun();
bp3->fun();
D1 *dp1=&d1;
D2 *dp2=&d2;
dp1->f2();
dp2->f2();
return 0;
}
输出结果:
base_c
base_c
d1_c
base_c
d1_c
d2_c
d2_d
d1_d
base_d
d1_d
base_d
base_d
无论是多少级继承,构造函数总是先从基类开始,而析构函数就是先从本身开始到基类。
相关文章推荐
- C语言重要知识点总结(一)
- 关于c语言逆序输出
- c++友元方法
- C语言的整型溢出问题
- 爬爬爬之路:C语言(六) 函数篇
- C++类成员初始化
- 【C++】状态模式
- 【C++】强制类型转换(static_cast,reinterpret_cast,const_cast,dynamic_cast,explicit)
- C++中顶层const和底层const
- 栈的链式存储方法的C语言实现
- C++中四种类型转换
- VC++中LNK2001错误
- 【C疯狂的教材】(四)C语言分支语句
- C++自定义函数
- C++ 静态局部变量用法详解
- 如何在ROS下编写自己的节点来订阅话题(C++)
- C++中创建、初始化以及删除 以变量为大小的动态二维数组
- c++primer——面向对象编程关键字
- C语言容易混淆的问题
- 排成一圈数3退出最后一人位置问题--C语言谭浩强版练习8.5