一道有意思的google面试题
今天看到一道google的面试题觉得挺有意思:
在C++文件中只declare class A, 但不以任何方式define class A, 是做什么用?
有兴趣的来讨论讨论
[解决办法]
抽象基类?
[解决办法]
class A
{
public:
virtual run() = 0;
};
[解决办法]
前置声明!~
class A;
class B
{
private:
A* a;
};
[解决办法]
用处可多了,比如用于 静态断言
static_assert
[解决办法]
我不知道
[解决办法]
关注
[解决办法]
能想到的也只有前置声明...
[解决办法]
不懂,没想到有什么用法。
前置声明,后面也一定有define的地方
[解决办法]
隐隐觉得和模板有关系……
[解决办法]
我觉得应该是前置声明吧,Scott在 <effective C++ ed.3> 中item31:为了将文件间的编译依存关系降到最低。
如果说在其它任何地方都没有定义,只能用测试驱动开发(TDD)解释了。
个人偏向于前者。
[解决办法]
只引入名字依赖。名字依赖是C++依赖关系中程度最低的。
[解决办法]
隐隐觉得和模板有关系……
---------
模板中用空定义比较多, class Something{};
[解决办法]
我能想到的就是两个作用.
1` 顺利度过编译期, 等待运行期.
2` 栈占用, 可以在运行期在这段空间内加载相应进程.
[解决办法]
前置说明啦
[解决办法]
前置声明 在后面也是要定义的吗
[解决办法]
不懂
[解决办法]
搜了一圈,还是没有找到解答
[解决办法]
在根本不需要定义的地方,只放一个声明,逻辑上可以降低类之间的依赖程度,物理上也可以提高编译速度。
[解决办法]
在C++文件中只declare class A, 但不以任何方式define class A
只能这么理解了,减少依赖性,具体就是Effective 3rd的Item 31.不过这样题目出得就有些小问题,因为这样肯定在某个文件中有class A的define,只不过不在该C++文件中,但是题目会让人有一定的误解。
[解决办法]
学习
[解决办法]
只声明没有定义的类可以以有限的方式来使它,不能用它来定义对象,但是可以用它来定义指针、引用等。
[解决办法]
template <class T>
Foo;
template <>
Foo <int>
{
//...
};
template <>
Foo <char>
{
//....
};
只能实例化Foo <int> Foo <char> ,因为实例化其他类时,没有定义
就想到这种
顶晨星老大的...
[解决办法]
前置声明...
[解决办法]
貌似可以先确定类的命名空间。
namespace A {
class B;
}
[解决办法]
不懂,要学的太多鸟
[解决办法]
那看来nevergone写得挺有道理
[解决办法]
是一个指示符的作用。在《Modern C++ Design》里用它来在遇到不期望的情况时确保编译出错用。
[解决办法]
的确是前置声明.
class A;
class B{
public:
A *fooA(A);
};
class A{
B *fooB();
};
如果前面不前置声明的话,编译器会报错.
声明之后让编译器延迟编译.
[解决办法]
呵呵,以上哪位能给出点具体例子?
[解决办法]
如果是在整个工程中只有class A 的声明,没有定义。其可以在侯捷所译的《C++设计新思维》中找到答案。在范型编程时会用到这样的声明。
[解决办法]
楼主既然看了Adrei Alexandrescu在 < <Modern C++ Design> > ,而且还看到了第二章还问这种问题实在是不应该。建议你再去看看2.9和第3章。
主要是用于有语法需求却无语义概念的地方,一般是玩些编译器的把戏。
比如 Loki里就是以“class NullType;”标记Typylist的末端。
[解决办法]
头文件要到处#include的,如果有定义,那不就重复定义了?
[解决办法]
class NullType ;也是可以的,2.9说得很清楚.没有必要跟我争这些细节,我也只是举个例子.主要要理解他们的作用,这样才能灵活运用.说白了,光声明没有定义主要是用于有语法需求却无语义概念的地方,只是告诉编译器有这样一个类型.一般是玩些编译期而非运行期的把戏。这难道不是楼主要得答案么?
[解决办法]
你还在跟我纠缠NullType,事实上2.9说得很清楚:
class NullType;
class EmptyType {};
确实Loki的源代码中是:class NullType {};但是我觉得class NullType;更好.这可以防止用户产生一个NullType对象.
"很明显,如果NullType没有定义的话,把它用到Typelist中肯定通不过编译. "从这句话可以看出你还没有真正理解Typelist.
不要再跟我讨论NullType.请体会下面这句话: "光声明而没有定义类,只是告诉编译器有这样一个类型眯名称,仅此而已 ".
[解决办法]
越看越糊涂呀
[解决办法]
不过应该是编译期的trick了
[解决办法]
nevergone()的代码不能编译。
至今,好像还没人给出实际例子。-_-!!!
[解决办法]
我倒是觉得中文版的说法更好,否则就会困惑于NullType和EmptyType
[解决办法]
我给的代码当然不能编译啊.
给个完整的代码
#include <iostream>
using namespace std;
template <class T>
class Foo;
template <>
class Foo <int>
{
public:
Foo()
{
cout < < "Foo <int> " < < endl;
}
};
template <>
class Foo <char>
{
public:
Foo()
{
cout < < "Foo <char> " < < endl;
}
};
int main()
{
Foo <int> a;
Foo <char> b;
Foo <float> c;
return 0;
}
在我的g++下.编译的结果是:
$ g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:32: 错误: 聚合 ‘Foo <float> c’ 类型不完全,无法被定义
因为没有提供Foo <T> 的定义.
注释那句Foo <float> c;
可以编译,我没有测试其他的编译器
[解决办法]
好的,我晕啊,
上面的代码没有 class 关键字,我说怎么不能编译。。。
------解决方案--------------------
哦.
忘记写了. 不好意思 ^0^
那天是徒手写的
[解决办法]
哈哈,是我晕,不怪你。
各位看官,现在 nevergone 写出了第一种用途。
不知道上面的TypeList情况如何。。。
[解决办法]
我的理解是可以用来区别有相同属性的不同模块或事物。
比如:
class _AudioModule;
class _VideoModule;
template <typename T>
struct SomeAttribute
{
// 这里是属性的一些数据
// 但是在这里并没有用到具体的类型T
}
typedef SomeAttribute <_AudioModule> AudioModule_Attribute
typedef SomeAttribute <_VideoModule> VideoModule_Attribute
也可以理解为定义一些类型吧
这里开始的两个类都是没有定义的,可能我的解释不是很清楚。
[解决办法]
用做模块之间的接口
[解决办法]
下面是一个应用的地方:
class A;
class __declspec(dllimport) B
{
public:
void DoSomething( A * pA );
};
这里假设是B是一个导出类,想暴露类B,但是不想暴露跟B有关联的类A,可以在给客户的.h文件里使用这种方式的声明,让客户得以编译通过。在客户的工程中,任何地方都找不到类A的定义。
[解决办法]
以前常用的一个方式是:
class MyClassInternal;
class __declspec(dllimport) MyClass
{
public:
void do1();
void do2();
private:
MyClassInternal * m_internal;
};
这样这个类的内部实现给彻底隐藏了。
[解决办法]
robotom的例子确实不错。
就是句柄类的用法,这样做的话,在库和框架中都能应用得到。
[解决办法]
可以用于实现类似Loki中的TypeList,这里有一个简单的TypeList,只能用来判断一个类型T是build-in类型还是class类型:
typelist.h
--------------------------------------------
#ifndef TYPELIST_H
#define TYPELIST_H
template <class T, class U>
struct _TypeList {
typedef T first;
typedef U rest;
};
//struct __class_type {
//};
struct __class_type;
struct __true_type {
};
struct __false_type {
};
typedef _TypeList <char,
_TypeList <signed char,
_TypeList <unsigned char,
_TypeList <short,
_TypeList <unsigned short,
_TypeList <int,
_TypeList <unsigned int,
_TypeList <long,
_TypeList <unsigned long,
_TypeList <float,
_TypeList <double,
_TypeList <long double, __class_type> > > > > > > > > > > > PremierList;
template <class T, class L = PremierList>
struct _Find {
static const bool value = _Find <T, typename L::rest> ::value;
};
template <class T, class U>
struct _Find <T, _TypeList <T, U> > {
static const bool value = true;
};
template <class T, class U>
struct _Find <T*, U> {
static const bool value = true;
};
template <class T, class U>
struct _Find <const T*, U> {
static const bool value = true;
};
template <int N, class U>
struct _Find <const char [N], U> {
static const bool value = true;
};
template <class T>
struct _Find <T, __class_type> {
static const bool value = false;
};
template <bool isPremier>
struct type_traits;
template <>
struct type_traits <true> {
typedef __true_type isPremier;
};
template <>
struct type_traits <false> {
typedef __false_type isPremier;
};
template <class T>
typename type_traits <_Find <T> ::value> ::isPremier
is_premier() {
return type_traits <_Find <T> ::value> ::isPremier();
}
#endif /*TYPELIST_H*/
typelist.cpp
-----------------------------------------
#include "typelist.h "
#include <iostream>
#include <string>
using namespace std;
template <class T>
void fun_impl(const T &s, __true_type) {
cout < < "premier type : " < < s < < endl;
}
template <class T>
void fun_impl(const T &s, __false_type) {
cout < < " class type : " < < s < < endl;
}
template <class T>
void fun(const T &s) {
fun_impl(s, is_premier <T> ());
}
int main() {
int i = 100;
int &ri = i;
int *pi = &i;
fun(i);
fun(ri);
fun(pi);
fun(3.15);
fun( "a c-style string ");
fun(string( "a std::string "));
return 0;
}
[解决办法]
暂时不懂
[解决办法]
你说的typedef实现方法是这个意思吗?
template <class T, class L = PremierList>
struct _Find {
//static const bool value = _Find <T, typename L::rest> ::value;
typedef value_type _Find <T, typename L::rest> ::value_type;
};
这个我也考虑过,不过好像编译不过
好像C++标准规定整形值可以在类中直接初始化,当然bool也应该算是整形吧
:)
[解决办法]
呵呵,谢谢,我还正郁闷不能这样写呢
确实是我写反了:
typedef typename _Find <T, typename L::rest> ::value_type value_type;
-------------------------------
这样的话就可以避免很多不必要的东西了