C++经典问答——读书笔记

1、不要在C++中调用longjmp,因为他会打破析构函数将被调用的顺序。
http://blog.sina.com.cn/s/blog_4d8498800100bonm.html

2.inline函数是否可以访问静态成员变量
可以啊,内联函数就相当于把函数展开,所以就相当于一系列语句,并不是真正的函数。
可以,inline 只是提供给编译器的一个建议,具体怎么做要看实际情况而定,比如说如果函数内出现循环,那么编译器通常不会将其内联。而且是否内联可以通过一系列编译选项和宏来控制,即便如此,具体怎么做仍要看编译器,也可以使用 #pragma auto_inline( [{on | off}] ) 来告知编译器使之自动决定是否内联某些函数 。对于直接在类定义内部实现的函数就相当于前面加上 inline 关键字。

综上所述,内联函数在功能上与普通函数相同 。

3、C++函数中那些不可以被声明为虚函数
常见的不不能声明为虚函数的有:普通函数(非成员函数);静态成员函数;内联成员函数;构造函数;友元函数。

(1).为什么C++不支持普通函数为虚函数?

普通函数(非成员函数)只能被overload,不能被override,声明为虚函数也没有什么意思,因此编译器会在编译时邦定函数。

(2).为什么C++不支持构造函数为虚函数?

这个原因很简单,主要是从语义上考虑,所以不支持。因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。(这不就是典型的悖论)

(3).为什么C++不支持内联成员函数为虚函数?
其实很简单,那内联函数就是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能够准确的执行自己的动作,这是不可能统一的。(再说了,inline函数在编译时被展开,虚函数在运行时才能动态的邦定函数)

4.为什么C++不支持静态成员函数为虚函数?
这也很简单,静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,他也没有要动态邦定的必要性。

5.为什么C++不支持友元函数为虚函数?
因为C++不支持友元函数的继承,对于没有继承特性的函数没有虚函数的说法。
*********************************************************************

1.顶层函数:多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层函数不属于成员函数,是不能被继承的。

2.构造函数:
(1)构造函数不能被继承,因而不能声明为virtual函数

(2)构造函数一般是用来初始化对象,只有在一个对象生成之后,才能发挥多态作用,如果将构造函数声明为virtual函数,则表现为在对象还没有生成的情

5、什么时候调用拷贝构造函数?
通过数值传递、数值返回、明确地拷贝一个对象的时候。

6、当使用布局new语法时,程序员将单独承担释放对象的责任。通过明确地调用析构函数可以做到这一点,它是少有的几个需要明确调用析构函数的情况之一。

 
  1. using namespace std;
  2. //在构造函数中调用虚函数,不会产生多态的效果,只会调用自己的成员函数
  3. class Base
  4. {
  5. public:
  6.     Base();
  7.     virtual void f();
  8.     virtual ~Base(){}
  9. };
  10. class Derived : public Base
  11. {
  12. public:
  13.     Derived();
  14.     virtual void f();
  15. };
  16. Base::Base()
  17. {
  18.     cout<<"Base::Base() calling f()!"<<endl;
  19.     f(); //为了明了,此处应改为Base::f();
  20. }
  21. void Base::f()
  22. {
  23.     cout<<"Base::f()!"<<endl;
  24. }
  25. Derived::Derived():Base()
  26. {
  27.     cout<<"Derived::Derived() calling f()!"<<endl;
  28.     f(); //为了明了,此处应改为Derived::f();
  29. }
  30. void Derived::f()
  31. {
  32.     cout<<"Derived::f()!"<<endl;
  33. }
  34. int main()
  35. {
  36.     cout<<"Create a Derived!"<<endl;
  37.     Derived d;
  38.     return 0;
  39. }

private:和protected:赋值运算符返回的是什么?
返回对this对象的一个引用或者void

private:和protected:赋值运算符不必返回*this,这是因为该类的运算符只有非常少的用户,因此限制了返回*this的优点。

我们经常声明赋值运算符为private:以便阻止用户对该类的对象赋值。
为了防止偶然一个成员函数或者一个友元函数调用,我们经常不对其进行定义。

在抽象类中,我们经常把赋值运算符声明为:protected:以便确保当目标是一个抽象类的引用时,赋值操作不会发生。

如何在派生类内使用赋值运算符?
派生类中的赋值运算符首先调用其直接基类的赋值运算符,然后在调用它的成员对象的赋值运算符。

 
  1. /假如基类的赋值运算符是虚拟的,那么派生类应该做什么?
  2. //开发人员应该覆盖基类的赋值运算符,并且提供一个重载的赋值运算符。
  3. #include <iostream>
  4. using namespace std;
  5. class B
  6. {
  7. public:
  8.     virtual ~B();
  9.     virtual B& operator= (const B& b);
  10. };
  11. B::~B(){}
  12. B& B::operator= (const B& b)
  13. {
  14.     cout<<"B::operator= (const B& b)"<<endl;
  15.     return *this;
  16. }
  17. class D : public B
  18. {
  19. public:
  20.     virtual D& oeprator= (const B& b);  //覆盖父类的
  21.     D& operator= (const D& d);          //重载
  22. };
  23. D& D::operator= (const B& b) //覆盖
  24. {
  25.     cout<<"D::operator= (const B& b)"<<endl;
  26.     return *this;
  27. }
  28. D& D::operator= (const D& d)
  29. {
  30.     cout<<"D::operator= (const D& d)"<<endl;
  31.     return *this;
  32. }
  33. void Sample(D& d, B&b, D& d2, B& b2)
  34. {
  35.     cout<<"d = d2: "; d = d2;
  36.     cout<<"d = b2: "; d = b2;
  37.     cout<<"b = b2: "; b = b2;
  38.     cout<<"b = d2: "; b = d2;
  39. }
  40. int main()
  41. {
  42.     D d, b, d2, b2;
  43. //  Sample(d, b, d2, b2);
  44.     return 0;
  45. }

什么是最终类/
最终类(也称叶子类)是一个永久地禁止产生派生类的类。
仅当设计者决定永久地禁止任何将来的类从一个类派生时,才能声明该类为最终类。
C++不支持&ldquo;finnal&rdquo;关键词,因此我们一般只是对其加以注释。

使编译器强制某个类成为最终类并不困难:只需使构造函数private:并且提供public:static create()成员函数。这样阻止派生类的存在,因为派生类不能调用最终类(private:)构造函数。

最终类不应该有protected:数据成员——它所有的数据成员都应该是private:。类似地,最终类也不应该声明任何新的虚拟函数(尽管它经常覆盖继承的虚拟函数)。

转载: http://blog.csdn.net/wangyangkobe/article/details/6118748

留下评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据