其他主题

const_cast运算符

C++提供 const_cast运算符,可以强制去除变量的const 和 volatile 属性. 如

const char* maximum(const char*first,const char* second);
......
char* maxPtr = const_cast<char*>(maximum(s1,s2));

如果没有const_cast<char*>,编译器将会报错,因为无法将const char赋值给char

关于volatile

volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序:

short flag;
void test()
{
	do1();
	while (flag == 0);
	do2();
}

这段程序等待内存变量flag的值变为1(怀疑此处是0,有点疑问,)之后才运行do2()。变量flag的值由别的程序更改,这个程序可能是某个硬件中断服务程序。例如:如果某个按钮按下的话,就会对DSP产生中断,在按键中断程序中修改flag为1,这样上面的程序就能够得以继续运行。但是,编译器并不知道flag的值会被别的程序修改,因此在它进行优化的时候,可能会把flag的值先读入某个寄存器,然后等待那个寄存器变为1。如果不幸进行了这样的优化,那么while循环就变成了死循环,因为寄存器的内容不可能被中断服务程序修改。为了让程序每次都读取真正flag变量的值,就需要定义为如下形式:

volatile short flag;

所以为了安全起见,只要是等待别的程序修改某个变量的话,就加上volatile关键字。
volatile的本意是“易变的”,由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。

mutable类成员

可以用来说明一个类中的成员总是可以被修改,即使它是在const成员函数中被调用

class test
{
public:
	int getValue() const
	{
		times++;          // times可修改
		return value;      
	}
private:
	int value;
	mutable int times=0;
}
	

命名空间

运算符关键字

C++ 提供运算符关键字代替相应运算符

运算符运算符关键字描述
逻辑运算符关键字
&&and逻辑与
orl逻辑或
!not逻辑非
!=不等运算符关键字不等
位运算符关键字
&bitand位与
bitor位或
^xor位异或
~compl按位取反
按位赋值运算符
&=and_eq
or_eq
^=xor_eq

指向类成员的指针(.* 和 ->*)

上代码

int main()
{
    Test test;
    test.value = 8;
    arrowStar(&test);
    dotStar(&test);
    return 0;
}
void arrowStar(Test* testPtr)
{
    void (Test::*funcPtr)() = &Test::func;
    (testPtr->*funcPtr)();       //调用
    ((*testPtr).*funcPtr)();     //调用
}
void dotStar(Test* testPtr)
{
    int (Test::*vPtr) = &Test::value;
    cout << (*testPtr).*vPtr << endl; //调用
}

输出:
In func
In func
8
声明一个指向类成员的指针——类名:: *,如 Test:: *.
(Test::*funcPtr)声明了一个指向类成员指针名 funcPtr, 必须用圆括号括起来。
左括号左侧void为成员函数返回值类型,右括号右侧()为成员函数参数列表,此处为空。
&Test::func,取成员函数地址。
. * 和 -> *为两种调用运算符。

多重继承

多重继承声明

class Drived: public Base1, public Base2, private Base3
{
	public:
		Drived(double,char,int);
		int getData() const;
	private:
		int real;
}

构造函数的初始化

Drived(double d,char c,int i,int r):Base1(d),Base2(c),Base3(i),real(r)
{
}

从多个基类继承同名的成员函数的二义性问题

调用时加入二元作用域运算符解决二义性问题,如:


Drived drive;
drive.Base1::func();
drive.Base2::func();

分别调用Base1和Base2中名为func的函数。
Base1和Base2类型的父指针都可以指向Drived类型地址

菱形继承的二义性问题

会导致子类中包含两个相同的间接基类成员的副本,存在二义性问题,可使用virtual 基类继承(纯虚)来解决间接继承一个基类的多个副本问题。

//***********菱形继承中的二义性问题***************
//*************使用virtual继承*************

#include <iostream>

using namespace std;

class Base
{
    public:
        virtual void print() const = 0;  //纯虚函数
};

class DrivedOne : virtual public Base   //virtual基类继承
{
    public:
        void print() const
        {
            cout << "DrivedOne\n";
        }
};

class DrivedTwo : virtual public Base   //virtual基类继承
{
    public:
        void print() const
        {
            cout << "DrivedTwo\n";
        }
};

class Multiple: public DrivedOne,public DrivedTwo
{
    public:
        void print() const
        {
            DrivedTwo::print();     //为避免二义性,使用二元域分辨符
        }
};

int main()
{
    Multiple both;
    DrivedOne one;
    DrivedTwo two;

    Base *base[3];
    base[0] = &both;
    base[1] = &one;
    base[2] = &two;

    for (int i = 0; i < 3;i++)
        base[i]->print();       //多态调用

    return 0;
}

输出:
DrivedTwo
DrivedOne
DrivedTwo

如果不使用virtual public Base,base[0] = &both;将发生错误
由于DrivedOne和DrivedTwo都使用virtual继承类 Base 的成员,所以编译器保证只有一个 Base 类子对象继承到类 Multiple中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值