[2016-05-13][C++若干问题]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[2016-05-13][C++若干问题]相关的知识,希望对你有一定的参考价值。

[2016-05-13][C++若干问题]

有错请指出,有错请指出,有错请指出,有错请指出,有错请指出,有错请指出,

下面的结论都是在VS下测试的,也许其他编译器会出现不同情况,

  • 比如下面这句,在VS下不能编译,但是在其他编译器能编译(华工OJ支持这种写法)
    1. int n = 5;
    2. int a[n];

1. 关于复制构造函数的某个特殊情况,

  1. A g(){ return A();}
  2. A c = g();
  • 这种情况,复制构造函数只调用了一次,实际上并没有创建匿名对象,匿名对象直接变成了声明的c,
  1. A c;
  2. c = g();
  • 如果是普通的赋值语句,那么它会先调用赋值构造函数来创建匿名对象,在调用”=”重载来进行赋值
  1. g();
  • 这个情况就会创建匿名对象,但是在函数结束之和,就会销毁(调用~A());
  1. "测试用代码"
  2. #include<iostream>
  3. using namespace std;
  4. class A{
  5. public:
  6. int a;
  7. A(int c = 0):a(c){
  8. cout<<"**********In A()\\n";
  9. cout<<this<<"\\n";
  10. cout<<"A:Constructor\\n";
  11. cout<<"******Out A()\\n";
  12. }
  13. A(A & b){
  14. cout<<"**********In Copy_A()\\n";
  15. cout<< & b <<" to "<<this<<"\\n";
  16. cout<<"B:Copy_Constructor\\n";
  17. a = b.a;
  18. cout<<"**********Out copy_A()\\n";
  19. }
  20. ~A(){
  21. cout<<this<<"~A\\n";
  22. }
  23. A operator = (const A & b){
  24. cout<<"Operator =\\n";
  25. a = b.a;
  26. return *this;
  27. }
  28. };
  29. A g(){
  30. cout<<"In g()\\n";
  31. A c;
  32. cout<<"before g() return\\n";
  33. return c;
  34. }
  35. int main(){
  36. //A c = g();
  37. A c;
  38. c = g();
  39. cout<<"C is:"<<&c<<"\\n";
  40. //g();
  41. return 0;
  42. }

2. [2016-04-23][使用复制构造函数的时候,为什么没有调用构造函数来构造临时对象]

就是在

  1. Array operatpr +
  2. return tmp;//Array的某变量

中返回一个对象
然后中途会进入到tmp拷贝到临时对象的复制构造函数中,但是在这个函数里面使用this查看变量,发现this的元素没有初始化,也就是没有调用构造函数(不管是默认的还是复制的)!!!
解决办法:在构造函数里面调用一次构造函数.

3.关于构造函数的调用顺序

  • 基类构造函数 —> 成员对象的构造函数 —> 派生类的构造函数

4.关于符号重载的若干问题

  • “=”重载,”=”只能重载为非静态成员函数
  • 支持友元函数重载的必要性
    1. class qhy;
    2. qhy a,b;
    3. a = a + b;//(1)
    4. a = b + 1;//(2)
    5. a = 1 + b;//(3)
    • 上面 “+” 重载,假设是成员函数的重载,
    • 对于(1)来说,只要有参数为qhy的重载,就合法
    • 对于(2)来说,只要qhy有参数含int的构造函数,或者是参数为int的”+”重载,就合法
    • 对于(3)来说,无论qhy有什么东西,都是非法的,因为 1 + b调用的是 int类型(1的类型) 对于”+”的重载,显然系统自带的类型,没有参数是qhy类型的”+”重载
    • 为了解决上面(3)的情况,就需要使用友元函数重载 “+” 号,这样,只要”+”一边有qhy类型,就一定调用qhy里面”+”的友元重载
    • 一些习惯
  • 运算符操作需要修改对象,用成员函数重载
  • 运算符操作数希望有隐式转换,使用友元重载
  • 不能用友元重载的符号
    • = () [] ->
  • 必须友元
    • >>  <<

5.关于类中的静态成员

  • 只有静态常量整型数据成员才可以在类中初始化
    1. class qhy{
    2. static int a = 0; // 非法!
    3. static const int b = 0; //合法!
    4. };
  • 非常量静态成员初始化和普通变量的初始化一样,并且在类外初始化

6.类中的非静态常量,要在构造函数中初始化,并且只能使用初始列表初始化

  • 普通成员
  1. class qhy{
  2. public:
  3. const int a;
  4. qhy(int _a):a(_a){}//合法!!
  5. qhy(int _a){a = _a;}//非法
  6. };
  • 数组成员
  1. class qhy{
  2. public:
  3. const int a[2];//这个没办法初始化,还是使用静态成员数组吧
  4. static const int b[2] = {1,2};//非法!!,正确姿势请看c
  5. static const int c[2] ;
  6. };
  7. const int qhy::c[2] = {1,2};

7.关于类型转换

  • 可以通过构造函数实现类型的转换,就比如上面的”+”重载,假设重载参数类型只有qhy,但是调用的时候,其中一个参数不是qhy,假设是int,这个时候会看构造函数是否有int的重载版本,有就调用它,把int转换成qhy
  • 类型转换函数
    1. ClassX::operator Type(){
    2. //do something
    3. return Type_Value;
    4. }
  • 例子
    1. class qhy{
    2. public:
    3. int a;
    4. operator int(){return a;}
    5. };
    6. int main(){
    7. qhy a;a.a = 10;
    8. cout<<int(a);
    9. }

8.类中重名成员与函数

  • 重名成员
    1. class Base{
    2. public:
    3. int a;
    4. Base():a(0){}
    5. };
    6. class qhy : public Base{
    7. public:
    8. int a;
    9. qhy():a(1){}
    10. };
    11. int main(){
    12. qhy a;
    13. cout<<a.a<<" "<<a.Base::a<<"\\n";
    14. //1 0
    15. }
  • 重名函数
    • 用法和上面类似

9.多重继承:一个类可以继承多个类

10.虚继承:若多个基类来个同一个基类,希望只继承一次,就是用虚继承

  • 非虚继承,调用了两次B的构造函数
    技术分享

  • 虚继承,调用了一次B的构造函数
    技术分享

    • 声明,继承前面加上virtual

      1. class qhy :virtual public Base{};
    • 虚继承的最高级的基类,就是上面的B,在D的构造函数中提供参数,不受B1,B2构造函数的影响

11.基类的初始化

  • 在构造函数初始化列表提供初始化参数,变量名变成基类镜子
  1. class qhy :public Base{
  2. qhy(int a):Base(a){};
  3. };
  • 继承基类的顺序决定了构造的顺序
  1. class qhy :public Base1,public Base2{};//先调用Base1的构造函数,在调用Base2的构造函数

12.使用指针引用派生类

  • 可以正常访问基类成员
  • 必须强制转换成派生类指针后,才能访问派生类的成员

13.使用派生类指针引用基类对象

  • 必须强制转换成基类指针之后,才能访问到基类对象
    小结:根据指针类型调用指针类型对应的函数,强制转换相当于加上了作用域符::

    1. class Base{
    2. public:
    3. int a,b;
    4. Base():a(0),b(1){}
    5. };
    6. class qhy:public Base{
    7. public:
    8. int b,c;
    9. qhy():b(2),c(3){}
    10. };
    11. int main(){
    12. qhy *pq;Base *pb;
    13. qhy q;Base b;
    14. cout<<b.a<<" "<<b.b<<" "<<q.b<<" "<<q.c<<"\\n";//0 1 2 3
    15. pb = &q;//使用基类指针引用派生类
    16. cout<<pb->a<<" "<<pb->b<<"\\n";//0 1
    17. //cout<<pb->c<<"\\n";//错误,在Base中c不存在
    18. cout<<((qhy*)pb)->a<<" "<<((qhy*)pb)->b<<" "<<((qhy*)pb)->c<<"\\n";//0 2 3,b访问到的是qhy的b
    19. //使用派生指针引用基类
    20. //pq = &b;//错误,类型不对
    21. pq = (qhy*)&b;
    22. cout<<pq->b<<pq->c;//乱码,因为b,c不存在
    23. return 0;
    24. }

14.虚函数

  • 上面,如果想用基类指针调用派生类对应的函数,每次都要强制转换一下,好麻烦,解决办法:使用虚函数
    • 即声明成虚函数之后,不再受到指针类型的影响,直接调用本身的函数
  • 虚函数的作用:使用基类指针引用派生类对象时,直接调用派生类对象对应版本的函数
  • 声明方法,在函数声明前面加上 virtual
  • 纯虚函数:只有声明没有定义的函数,(需要在派生类中定义,否则不能实例化)

    1. virtual int func() = 0;
    • 抽象类:含有纯虚函数的类
  • 虚析构函数:如果是动态创建的对象,并且使用基类指针来引用的话,delete的时候,调用的是基类的析构函数,如果希望调用派生类对应的析构函数,就把析构函数声明为虚函数

15.public,private,protected属性

  • 类成员的属性:
    • private:成员只能在类内部和友元内访问,子类和外部都不能访问
    • protected:类内部,友元,子类都可访问,类外部不能访问
    • public:谁都可以乱搞
  • 类的继承方式
- 基类成员属性 public protected private
继承类型 ↓继承之后的属性,属性性质→ 所有都可见 类内部,友元,子类可见 类内部,友元可见,子类不可见
public 完全不变 public protected private
protected public变成protectd,其他保持 protected protected private
private 全部变成private private private private









以上是关于[2016-05-13][C++若干问题]的主要内容,如果未能解决你的问题,请参考以下文章

Django 模型继承和外键

一周小结(2016-05-09~2016-05-13)

2016.05.13-2016.05.19这周工作时间和内容

关于数据库主键和外键

关于数据库主键和外键

mysql级联更新的两种方式:触发器更新和外键